Date: | 2011-06-06 05:41:21 (12 years 6 months ago) |
---|---|
Author: | Maarten ter Huurne |
Commit: | daa746b23c77cf0c1bcccd25fde0a17ff778b2d6 |
Message: | MIPS: JZ4740: SLCD framebufer driver. This driver sends the frame buffer to a smart LCD controller, that is a controller with its own video memory. It is a squashed version of development done in the jz-2.6.38 branch. |
Files: |
arch/mips/include/asm/mach-jz4740/gpio.h (2 diffs) arch/mips/include/asm/mach-jz4740/jz4740_fb.h (2 diffs) drivers/video/Kconfig (1 diff) drivers/video/Makefile (1 diff) drivers/video/jz4740_fb.c (1 diff) drivers/video/jz4740_lcd.h (1 diff) drivers/video/jz4740_slcd.h (1 diff) drivers/video/jz4740_slcd_fb.c (1 diff) drivers/video/jz4740_slcd_panels.c (1 diff) |
Change Details
arch/mips/include/asm/mach-jz4740/gpio.h | ||
---|---|---|
253 | 253 | #define JZ_GPIO_MEM_WAIT JZ_GPIO_PORTC(27) |
254 | 254 | #define JZ_GPIO_MEM_FRE JZ_GPIO_PORTC(28) |
255 | 255 | #define JZ_GPIO_MEM_FWE JZ_GPIO_PORTC(29) |
256 | /* Pins have different assignment in SLCD mode */ | |
257 | #define JZ_GPIO_SLCD_RS JZ_GPIO_PORTC(19) | |
258 | #define JZ_GPIO_SLCD_CS JZ_GPIO_PORTC(20) | |
256 | 259 | |
257 | 260 | #define JZ_GPIO_FUNC_LCD_DATA0 JZ_GPIO_FUNC1 |
258 | 261 | #define JZ_GPIO_FUNC_LCD_DATA1 JZ_GPIO_FUNC1 |
... | ... | |
284 | 287 | #define JZ_GPIO_FUNC_MEM_WAIT JZ_GPIO_FUNC1 |
285 | 288 | #define JZ_GPIO_FUNC_MEM_FRE JZ_GPIO_FUNC1 |
286 | 289 | #define JZ_GPIO_FUNC_MEM_FWE JZ_GPIO_FUNC1 |
290 | #define JZ_GPIO_FUNC_SLCD_RS JZ_GPIO_FUNC1 | |
291 | #define JZ_GPIO_FUNC_SLCD_CS JZ_GPIO_FUNC1 | |
287 | 292 | |
288 | 293 | |
289 | 294 | #define JZ_GPIO_MEM_ADDR19 JZ_GPIO_PORTB(22) |
arch/mips/include/asm/mach-jz4740/jz4740_fb.h | ||
---|---|---|
30 | 30 | JZ_LCD_TYPE_DUAL_COLOR_STN = 10, |
31 | 31 | JZ_LCD_TYPE_DUAL_MONOCHROME_STN = 11, |
32 | 32 | JZ_LCD_TYPE_8BIT_SERIAL = 12, |
33 | JZ_LCD_TYPE_SMART_PARALLEL_8_BIT = 1 | (1 << 5), | |
34 | JZ_LCD_TYPE_SMART_PARALLEL_16_BIT = 0 | (1 << 5), | |
35 | JZ_LCD_TYPE_SMART_PARALLEL_18_BIT = 2 | (1 << 5), | |
36 | JZ_LCD_TYPE_SMART_SERIAL_8_BIT = 1 | (3 << 5), | |
37 | JZ_LCD_TYPE_SMART_SERIAL_16_BIT = 0 | (3 << 5), | |
38 | JZ_LCD_TYPE_SMART_SERIAL_18_BIT = 2 | (3 << 5), | |
33 | 39 | }; |
34 | 40 | |
35 | 41 | #define JZ4740_FB_SPECIAL_TFT_CONFIG(start, stop) (((start) << 16) | (stop)) |
... | ... | |
62 | 68 | |
63 | 69 | unsigned pixclk_falling_edge:1; |
64 | 70 | unsigned date_enable_active_low:1; |
71 | unsigned chip_select_active_low:1; | |
72 | unsigned register_select_active_low:1; | |
65 | 73 | }; |
66 | 74 | |
67 | 75 | #endif |
drivers/video/Kconfig | ||
---|---|---|
2363 | 2363 | help |
2364 | 2364 | Framebuffer support for the JZ4740 SoC. |
2365 | 2365 | |
2366 | config FB_JZ4740_SLCD | |
2367 | tristate "JZ4740 Smart LCD framebuffer support" | |
2368 | depends on FB && MACH_JZ4740 | |
2369 | select FB_SYS_FILLRECT | |
2370 | select FB_SYS_COPYAREA | |
2371 | select FB_SYS_IMAGEBLIT | |
2372 | help | |
2373 | This is the frame buffer device driver for the JZ4740 Smart LCD controller. | |
2374 | If you say Y here, please say N to 'JZ4740 LCD framebuffer support'. | |
2375 | ||
2376 | config JZ_SLCD_ILI9325 | |
2377 | bool "ILI9325 Smart LCD panel" | |
2378 | depends on FB_JZ4740_SLCD | |
2379 | ||
2380 | config JZ_SLCD_ILI9331 | |
2381 | bool "ILI9331 Smart LCD panel" | |
2382 | depends on FB_JZ4740_SLCD | |
2383 | ||
2384 | config JZ_SLCD_ILI9338 | |
2385 | bool "ILI9338 Smart LCD panel" | |
2386 | depends on FB_JZ4740_SLCD | |
2387 | ||
2388 | config JZ_SLCD_LGDP4551 | |
2389 | bool "LG LGDP4551 Smart LCD panel" | |
2390 | depends on FB_JZ4740_SLCD | |
2391 | ||
2392 | config JZ_SLCD_SPFD5420A | |
2393 | bool "SPFD5420A Smart LCD panel" | |
2394 | depends on FB_JZ4740_SLCD | |
2395 | ||
2366 | 2396 | config FB_MXS |
2367 | 2397 | tristate "MXS LCD framebuffer support" |
2368 | 2398 | depends on FB && ARCH_MXS |
drivers/video/Makefile | ||
---|---|---|
140 | 140 | obj-$(CONFIG_FB_MSM) += msm/ |
141 | 141 | obj-$(CONFIG_FB_NUC900) += nuc900fb.o |
142 | 142 | obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o |
143 | obj-$(CONFIG_FB_JZ4740_SLCD) += jz4740_slcd_fb.o jz4740_slcd_panels.o | |
143 | 144 | obj-$(CONFIG_FB_PUV3_UNIGFX) += fb-puv3.o |
144 | 145 | |
145 | 146 | # Platform or fallback drivers go here |
drivers/video/jz4740_fb.c | ||
---|---|---|
29 | 29 | #include <asm/mach-jz4740/jz4740_fb.h> |
30 | 30 | #include <asm/mach-jz4740/gpio.h> |
31 | 31 | |
32 | #define JZ_REG_LCD_CFG 0x00 | |
33 | #define JZ_REG_LCD_VSYNC 0x04 | |
34 | #define JZ_REG_LCD_HSYNC 0x08 | |
35 | #define JZ_REG_LCD_VAT 0x0C | |
36 | #define JZ_REG_LCD_DAH 0x10 | |
37 | #define JZ_REG_LCD_DAV 0x14 | |
38 | #define JZ_REG_LCD_PS 0x18 | |
39 | #define JZ_REG_LCD_CLS 0x1C | |
40 | #define JZ_REG_LCD_SPL 0x20 | |
41 | #define JZ_REG_LCD_REV 0x24 | |
42 | #define JZ_REG_LCD_CTRL 0x30 | |
43 | #define JZ_REG_LCD_STATE 0x34 | |
44 | #define JZ_REG_LCD_IID 0x38 | |
45 | #define JZ_REG_LCD_DA0 0x40 | |
46 | #define JZ_REG_LCD_SA0 0x44 | |
47 | #define JZ_REG_LCD_FID0 0x48 | |
48 | #define JZ_REG_LCD_CMD0 0x4C | |
49 | #define JZ_REG_LCD_DA1 0x50 | |
50 | #define JZ_REG_LCD_SA1 0x54 | |
51 | #define JZ_REG_LCD_FID1 0x58 | |
52 | #define JZ_REG_LCD_CMD1 0x5C | |
53 | ||
54 | #define JZ_LCD_CFG_SLCD BIT(31) | |
55 | #define JZ_LCD_CFG_PS_DISABLE BIT(23) | |
56 | #define JZ_LCD_CFG_CLS_DISABLE BIT(22) | |
57 | #define JZ_LCD_CFG_SPL_DISABLE BIT(21) | |
58 | #define JZ_LCD_CFG_REV_DISABLE BIT(20) | |
59 | #define JZ_LCD_CFG_HSYNCM BIT(19) | |
60 | #define JZ_LCD_CFG_PCLKM BIT(18) | |
61 | #define JZ_LCD_CFG_INV BIT(17) | |
62 | #define JZ_LCD_CFG_SYNC_DIR BIT(16) | |
63 | #define JZ_LCD_CFG_PS_POLARITY BIT(15) | |
64 | #define JZ_LCD_CFG_CLS_POLARITY BIT(14) | |
65 | #define JZ_LCD_CFG_SPL_POLARITY BIT(13) | |
66 | #define JZ_LCD_CFG_REV_POLARITY BIT(12) | |
67 | #define JZ_LCD_CFG_HSYNC_ACTIVE_LOW BIT(11) | |
68 | #define JZ_LCD_CFG_PCLK_FALLING_EDGE BIT(10) | |
69 | #define JZ_LCD_CFG_DE_ACTIVE_LOW BIT(9) | |
70 | #define JZ_LCD_CFG_VSYNC_ACTIVE_LOW BIT(8) | |
71 | #define JZ_LCD_CFG_18_BIT BIT(7) | |
72 | #define JZ_LCD_CFG_PDW (BIT(5) | BIT(4)) | |
73 | #define JZ_LCD_CFG_MODE_MASK 0xf | |
74 | ||
75 | #define JZ_LCD_CTRL_BURST_4 (0x0 << 28) | |
76 | #define JZ_LCD_CTRL_BURST_8 (0x1 << 28) | |
77 | #define JZ_LCD_CTRL_BURST_16 (0x2 << 28) | |
78 | #define JZ_LCD_CTRL_RGB555 BIT(27) | |
79 | #define JZ_LCD_CTRL_OFUP BIT(26) | |
80 | #define JZ_LCD_CTRL_FRC_GRAYSCALE_16 (0x0 << 24) | |
81 | #define JZ_LCD_CTRL_FRC_GRAYSCALE_4 (0x1 << 24) | |
82 | #define JZ_LCD_CTRL_FRC_GRAYSCALE_2 (0x2 << 24) | |
83 | #define JZ_LCD_CTRL_PDD_MASK (0xff << 16) | |
84 | #define JZ_LCD_CTRL_EOF_IRQ BIT(13) | |
85 | #define JZ_LCD_CTRL_SOF_IRQ BIT(12) | |
86 | #define JZ_LCD_CTRL_OFU_IRQ BIT(11) | |
87 | #define JZ_LCD_CTRL_IFU0_IRQ BIT(10) | |
88 | #define JZ_LCD_CTRL_IFU1_IRQ BIT(9) | |
89 | #define JZ_LCD_CTRL_DD_IRQ BIT(8) | |
90 | #define JZ_LCD_CTRL_QDD_IRQ BIT(7) | |
91 | #define JZ_LCD_CTRL_REVERSE_ENDIAN BIT(6) | |
92 | #define JZ_LCD_CTRL_LSB_FISRT BIT(5) | |
93 | #define JZ_LCD_CTRL_DISABLE BIT(4) | |
94 | #define JZ_LCD_CTRL_ENABLE BIT(3) | |
95 | #define JZ_LCD_CTRL_BPP_1 0x0 | |
96 | #define JZ_LCD_CTRL_BPP_2 0x1 | |
97 | #define JZ_LCD_CTRL_BPP_4 0x2 | |
98 | #define JZ_LCD_CTRL_BPP_8 0x3 | |
99 | #define JZ_LCD_CTRL_BPP_15_16 0x4 | |
100 | #define JZ_LCD_CTRL_BPP_18_24 0x5 | |
101 | ||
102 | #define JZ_LCD_CMD_SOF_IRQ BIT(15) | |
103 | #define JZ_LCD_CMD_EOF_IRQ BIT(16) | |
104 | #define JZ_LCD_CMD_ENABLE_PAL BIT(12) | |
105 | ||
106 | #define JZ_LCD_SYNC_MASK 0x3ff | |
107 | ||
108 | #define JZ_LCD_STATE_DISABLED BIT(0) | |
32 | #include "jz4740_lcd.h" | |
109 | 33 | |
110 | 34 | struct jzfb_framedesc { |
111 | 35 | uint32_t next; |
drivers/video/jz4740_lcd.h | ||
---|---|---|
1 | /* | |
2 | * Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de> | |
3 | * JZ4720/JZ4740 SoC LCD framebuffer driver | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU General Public License as published by the | |
7 | * Free Software Foundation; either version 2 of the License, or (at your | |
8 | * option) any later version. | |
9 | * | |
10 | * You should have received a copy of the GNU General Public License along | |
11 | * with this program; if not, write to the Free Software Foundation, Inc., | |
12 | * 675 Mass Ave, Cambridge, MA 02139, USA. | |
13 | * | |
14 | */ | |
15 | ||
16 | #ifndef __JZ4740_LCD_H__ | |
17 | #define __JZ4740_LCD_H__ | |
18 | ||
19 | #include <linux/bitops.h> | |
20 | ||
21 | #define JZ_REG_LCD_CFG 0x00 | |
22 | #define JZ_REG_LCD_VSYNC 0x04 | |
23 | #define JZ_REG_LCD_HSYNC 0x08 | |
24 | #define JZ_REG_LCD_VAT 0x0C | |
25 | #define JZ_REG_LCD_DAH 0x10 | |
26 | #define JZ_REG_LCD_DAV 0x14 | |
27 | #define JZ_REG_LCD_PS 0x18 | |
28 | #define JZ_REG_LCD_CLS 0x1C | |
29 | #define JZ_REG_LCD_SPL 0x20 | |
30 | #define JZ_REG_LCD_REV 0x24 | |
31 | #define JZ_REG_LCD_CTRL 0x30 | |
32 | #define JZ_REG_LCD_STATE 0x34 | |
33 | #define JZ_REG_LCD_IID 0x38 | |
34 | #define JZ_REG_LCD_DA0 0x40 | |
35 | #define JZ_REG_LCD_SA0 0x44 | |
36 | #define JZ_REG_LCD_FID0 0x48 | |
37 | #define JZ_REG_LCD_CMD0 0x4C | |
38 | #define JZ_REG_LCD_DA1 0x50 | |
39 | #define JZ_REG_LCD_SA1 0x54 | |
40 | #define JZ_REG_LCD_FID1 0x58 | |
41 | #define JZ_REG_LCD_CMD1 0x5C | |
42 | ||
43 | #define JZ_LCD_CFG_SLCD BIT(31) | |
44 | #define JZ_LCD_CFG_PS_DISABLE BIT(23) | |
45 | #define JZ_LCD_CFG_CLS_DISABLE BIT(22) | |
46 | #define JZ_LCD_CFG_SPL_DISABLE BIT(21) | |
47 | #define JZ_LCD_CFG_REV_DISABLE BIT(20) | |
48 | #define JZ_LCD_CFG_HSYNCM BIT(19) | |
49 | #define JZ_LCD_CFG_PCLKM BIT(18) | |
50 | #define JZ_LCD_CFG_INV BIT(17) | |
51 | #define JZ_LCD_CFG_SYNC_DIR BIT(16) | |
52 | #define JZ_LCD_CFG_PS_POLARITY BIT(15) | |
53 | #define JZ_LCD_CFG_CLS_POLARITY BIT(14) | |
54 | #define JZ_LCD_CFG_SPL_POLARITY BIT(13) | |
55 | #define JZ_LCD_CFG_REV_POLARITY BIT(12) | |
56 | #define JZ_LCD_CFG_HSYNC_ACTIVE_LOW BIT(11) | |
57 | #define JZ_LCD_CFG_PCLK_FALLING_EDGE BIT(10) | |
58 | #define JZ_LCD_CFG_DE_ACTIVE_LOW BIT(9) | |
59 | #define JZ_LCD_CFG_VSYNC_ACTIVE_LOW BIT(8) | |
60 | #define JZ_LCD_CFG_18_BIT BIT(7) | |
61 | #define JZ_LCD_CFG_PDW (BIT(5) | BIT(4)) | |
62 | #define JZ_LCD_CFG_MODE_MASK 0xf | |
63 | ||
64 | #define JZ_LCD_CTRL_BURST_4 (0x0 << 28) | |
65 | #define JZ_LCD_CTRL_BURST_8 (0x1 << 28) | |
66 | #define JZ_LCD_CTRL_BURST_16 (0x2 << 28) | |
67 | #define JZ_LCD_CTRL_RGB555 BIT(27) | |
68 | #define JZ_LCD_CTRL_OFUP BIT(26) | |
69 | #define JZ_LCD_CTRL_FRC_GRAYSCALE_16 (0x0 << 24) | |
70 | #define JZ_LCD_CTRL_FRC_GRAYSCALE_4 (0x1 << 24) | |
71 | #define JZ_LCD_CTRL_FRC_GRAYSCALE_2 (0x2 << 24) | |
72 | #define JZ_LCD_CTRL_PDD_MASK (0xff << 16) | |
73 | #define JZ_LCD_CTRL_EOF_IRQ BIT(13) | |
74 | #define JZ_LCD_CTRL_SOF_IRQ BIT(12) | |
75 | #define JZ_LCD_CTRL_OFU_IRQ BIT(11) | |
76 | #define JZ_LCD_CTRL_IFU0_IRQ BIT(10) | |
77 | #define JZ_LCD_CTRL_IFU1_IRQ BIT(9) | |
78 | #define JZ_LCD_CTRL_DD_IRQ BIT(8) | |
79 | #define JZ_LCD_CTRL_QDD_IRQ BIT(7) | |
80 | #define JZ_LCD_CTRL_REVERSE_ENDIAN BIT(6) | |
81 | #define JZ_LCD_CTRL_LSB_FISRT BIT(5) | |
82 | #define JZ_LCD_CTRL_DISABLE BIT(4) | |
83 | #define JZ_LCD_CTRL_ENABLE BIT(3) | |
84 | #define JZ_LCD_CTRL_BPP_1 0x0 | |
85 | #define JZ_LCD_CTRL_BPP_2 0x1 | |
86 | #define JZ_LCD_CTRL_BPP_4 0x2 | |
87 | #define JZ_LCD_CTRL_BPP_8 0x3 | |
88 | #define JZ_LCD_CTRL_BPP_15_16 0x4 | |
89 | #define JZ_LCD_CTRL_BPP_18_24 0x5 | |
90 | ||
91 | #define JZ_LCD_CMD_SOF_IRQ BIT(15) | |
92 | #define JZ_LCD_CMD_EOF_IRQ BIT(16) | |
93 | #define JZ_LCD_CMD_ENABLE_PAL BIT(12) | |
94 | ||
95 | #define JZ_LCD_SYNC_MASK 0x3ff | |
96 | ||
97 | #define JZ_LCD_STATE_DISABLED BIT(0) | |
98 | ||
99 | #endif /*__JZ4740_LCD_H__*/ |
drivers/video/jz4740_slcd.h | ||
---|---|---|
1 | /* | |
2 | * linux/drivers/video/jz4740_slcd.h | |
3 | * -- LCD panel definitions for Ingenic On-Chip SLCD frame buffer device | |
4 | * | |
5 | * Copyright (C) 2005-2007, Ingenic Semiconductor Inc. | |
6 | * Copyright (C) 2010, Maarten ter Huurne <maarten@treewalker.org> | |
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 version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | * | |
12 | */ | |
13 | ||
14 | #ifndef __JZ4740_SLCD_H__ | |
15 | #define __JZ4740_SLCD_H__ | |
16 | ||
17 | #include <asm/mach-jz4740/base.h> | |
18 | #include <linux/gpio.h> | |
19 | #include <linux/mutex.h> | |
20 | #include <linux/workqueue.h> | |
21 | ||
22 | /************************************************************************* | |
23 | * SLCD (Smart LCD Controller) | |
24 | *************************************************************************/ | |
25 | ||
26 | #define JZ_REG_SLCD_CFG 0xA0 /* SLCD Configure Register */ | |
27 | #define JZ_REG_SLCD_CTRL 0xA4 /* SLCD Control Register */ | |
28 | #define JZ_REG_SLCD_STATE 0xA8 /* SLCD Status Register */ | |
29 | #define JZ_REG_SLCD_DATA 0xAC /* SLCD Data Register */ | |
30 | #define JZ_REG_SLCD_FIFO 0xB0 /* SLCD FIFO Register */ | |
31 | ||
32 | /* SLCD Configure Register */ | |
33 | #define SLCD_CFG_BURST_BIT 14 | |
34 | #define SLCD_CFG_BURST_MASK (0x3 << SLCD_CFG_BURST_BIT) | |
35 | #define SLCD_CFG_BURST_4_WORD (0 << SLCD_CFG_BURST_BIT) | |
36 | #define SLCD_CFG_BURST_8_WORD (1 << SLCD_CFG_BURST_BIT) | |
37 | #define SLCD_CFG_DWIDTH_BIT 10 | |
38 | #define SLCD_CFG_DWIDTH_MASK (0x7 << SLCD_CFG_DWIDTH_BIT) | |
39 | #define SLCD_CFG_DWIDTH_18 (0 << SLCD_CFG_DWIDTH_BIT) | |
40 | #define SLCD_CFG_DWIDTH_16 (1 << SLCD_CFG_DWIDTH_BIT) | |
41 | #define SLCD_CFG_DWIDTH_8_x3 (2 << SLCD_CFG_DWIDTH_BIT) | |
42 | #define SLCD_CFG_DWIDTH_8_x2 (3 << SLCD_CFG_DWIDTH_BIT) | |
43 | #define SLCD_CFG_DWIDTH_8_x1 (4 << SLCD_CFG_DWIDTH_BIT) | |
44 | #define SLCD_CFG_DWIDTH_9_x2 (7 << SLCD_CFG_DWIDTH_BIT) | |
45 | #define SLCD_CFG_CWIDTH_BIT 8 | |
46 | #define SLCD_CFG_CWIDTH_MASK (0x3 << SLCD_CFG_CWIDTH_BIT) | |
47 | #define SLCD_CFG_CWIDTH_16BIT (0 << SLCD_CFG_CWIDTH_BIT) | |
48 | #define SLCD_CFG_CWIDTH_8BIT (1 << SLCD_CFG_CWIDTH_BIT) | |
49 | #define SLCD_CFG_CWIDTH_18BIT (2 << SLCD_CFG_CWIDTH_BIT) | |
50 | #define SLCD_CFG_CS_ACTIVE_LOW (0 << 4) | |
51 | #define SLCD_CFG_CS_ACTIVE_HIGH (1 << 4) | |
52 | #define SLCD_CFG_RS_CMD_LOW (0 << 3) | |
53 | #define SLCD_CFG_RS_CMD_HIGH (1 << 3) | |
54 | #define SLCD_CFG_CLK_ACTIVE_FALLING (0 << 1) | |
55 | #define SLCD_CFG_CLK_ACTIVE_RISING (1 << 1) | |
56 | #define SLCD_CFG_TYPE_PARALLEL (0 << 0) | |
57 | #define SLCD_CFG_TYPE_SERIAL (1 << 0) | |
58 | ||
59 | /* SLCD Control Register */ | |
60 | #define SLCD_CTRL_DMA_EN (1 << 0) | |
61 | ||
62 | /* SLCD Status Register */ | |
63 | #define SLCD_STATE_BUSY (1 << 0) | |
64 | ||
65 | /* SLCD Data Register */ | |
66 | #define SLCD_DATA_RS_DATA (0 << 31) | |
67 | #define SLCD_DATA_RS_COMMAND (1 << 31) | |
68 | ||
69 | /* SLCD FIFO Register */ | |
70 | #define SLCD_FIFO_RS_DATA (0 << 31) | |
71 | #define SLCD_FIFO_RS_COMMAND (1 << 31) | |
72 | ||
73 | /*************************************************************************/ | |
74 | ||
75 | struct jzfb { | |
76 | struct fb_info *fb; | |
77 | struct platform_device *pdev; | |
78 | void __iomem *base; | |
79 | struct resource *mem; | |
80 | struct jz4740_fb_platform_data *pdata; | |
81 | const struct jz_slcd_panel *panel; | |
82 | ||
83 | size_t vidmem_size; | |
84 | void *vidmem; | |
85 | dma_addr_t vidmem_phys; | |
86 | struct jzfb_framedesc *framedesc; | |
87 | dma_addr_t framedesc_phys; | |
88 | struct jz4740_dma_chan *dma; | |
89 | ||
90 | struct clk *ldclk; | |
91 | struct clk *lpclk; | |
92 | ||
93 | unsigned is_enabled:1; | |
94 | struct mutex lock; /* Protecting against running enable/disable in paralell */ | |
95 | ||
96 | struct delayed_work refresh_work; | |
97 | ||
98 | uint32_t pseudo_palette[16]; | |
99 | }; | |
100 | ||
101 | struct jz_slcd_panel { | |
102 | /* request and configure GPIO pins */ | |
103 | int (*init)(struct jzfb *jzfb); | |
104 | /* free GPIO pins */ | |
105 | void (*exit)(struct jzfb *jzfb); | |
106 | /* activate, reset and initialize */ | |
107 | void (*enable)(struct jzfb *jzfb); | |
108 | /* deactivate */ | |
109 | void (*disable)(struct jzfb *jzfb); | |
110 | }; | |
111 | ||
112 | const struct jz_slcd_panel *jz_slcd_panels_probe(struct jzfb *jzfb); | |
113 | ||
114 | #endif /*__JZ4740_SLCD_H__*/ |
drivers/video/jz4740_slcd_fb.c | ||
---|---|---|
1 | /* | |
2 | * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> | |
3 | * Copyright (C) 2010, Maarten ter Huurne <maarten@treewalker.org> | |
4 | * JZ4720/JZ4740 SoC LCD framebuffer driver | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the | |
8 | * Free Software Foundation; either version 2 of the License, or (at your | |
9 | * option) any later version. | |
10 | * | |
11 | * You should have received a copy of the GNU General Public License along | |
12 | * with this program; if not, write to the Free Software Foundation, Inc., | |
13 | * 675 Mass Ave, Cambridge, MA 02139, USA. | |
14 | * | |
15 | */ | |
16 | ||
17 | #include <linux/kernel.h> | |
18 | #include <linux/module.h> | |
19 | #include <linux/mutex.h> | |
20 | #include <linux/platform_device.h> | |
21 | ||
22 | #include <linux/clk.h> | |
23 | #include <linux/delay.h> | |
24 | ||
25 | #include <linux/console.h> | |
26 | #include <linux/fb.h> | |
27 | ||
28 | #include <linux/dma-mapping.h> | |
29 | ||
30 | #include <asm/mach-jz4740/dma.h> | |
31 | #include <asm/mach-jz4740/gpio.h> | |
32 | #include <asm/mach-jz4740/jz4740_fb.h> | |
33 | ||
34 | #include "jz4740_lcd.h" | |
35 | #include "jz4740_slcd.h" | |
36 | ||
37 | struct jzfb_framedesc { | |
38 | uint32_t next; | |
39 | uint32_t addr; | |
40 | uint32_t id; | |
41 | uint32_t cmd; | |
42 | } __attribute__((packed)); | |
43 | ||
44 | static struct fb_fix_screeninfo jzfb_fix __devinitdata = { | |
45 | .id = "JZ4740 SLCD FB", | |
46 | .type = FB_TYPE_PACKED_PIXELS, | |
47 | .visual = FB_VISUAL_TRUECOLOR, | |
48 | .xpanstep = 0, | |
49 | .ypanstep = 1, | |
50 | .ywrapstep = 0, | |
51 | .accel = FB_ACCEL_NONE, | |
52 | }; | |
53 | ||
54 | const static struct jz_gpio_bulk_request jz_slcd_ctrl_pins[] = { | |
55 | JZ_GPIO_BULK_PIN(LCD_PCLK), | |
56 | JZ_GPIO_BULK_PIN(SLCD_RS), | |
57 | JZ_GPIO_BULK_PIN(SLCD_CS), | |
58 | }; | |
59 | ||
60 | const static struct jz_gpio_bulk_request jz_slcd_data_pins[] = { | |
61 | JZ_GPIO_BULK_PIN(LCD_DATA0), | |
62 | JZ_GPIO_BULK_PIN(LCD_DATA1), | |
63 | JZ_GPIO_BULK_PIN(LCD_DATA2), | |
64 | JZ_GPIO_BULK_PIN(LCD_DATA3), | |
65 | JZ_GPIO_BULK_PIN(LCD_DATA4), | |
66 | JZ_GPIO_BULK_PIN(LCD_DATA5), | |
67 | JZ_GPIO_BULK_PIN(LCD_DATA6), | |
68 | JZ_GPIO_BULK_PIN(LCD_DATA7), | |
69 | JZ_GPIO_BULK_PIN(LCD_DATA8), | |
70 | JZ_GPIO_BULK_PIN(LCD_DATA9), | |
71 | JZ_GPIO_BULK_PIN(LCD_DATA10), | |
72 | JZ_GPIO_BULK_PIN(LCD_DATA11), | |
73 | JZ_GPIO_BULK_PIN(LCD_DATA12), | |
74 | JZ_GPIO_BULK_PIN(LCD_DATA13), | |
75 | JZ_GPIO_BULK_PIN(LCD_DATA14), | |
76 | JZ_GPIO_BULK_PIN(LCD_DATA15), | |
77 | JZ_GPIO_BULK_PIN(LCD_DATA16), | |
78 | JZ_GPIO_BULK_PIN(LCD_DATA17), | |
79 | }; | |
80 | ||
81 | static unsigned int jzfb_num_ctrl_pins(struct jzfb *jzfb) | |
82 | { | |
83 | return ARRAY_SIZE(jz_slcd_ctrl_pins); | |
84 | } | |
85 | ||
86 | static unsigned int jzfb_num_data_pins(struct jzfb *jzfb) | |
87 | { | |
88 | switch (jzfb->pdata->lcd_type) { | |
89 | case JZ_LCD_TYPE_SMART_PARALLEL_8_BIT: | |
90 | return 8; | |
91 | case JZ_LCD_TYPE_SMART_PARALLEL_16_BIT: | |
92 | return 16; | |
93 | case JZ_LCD_TYPE_SMART_PARALLEL_18_BIT: | |
94 | return 18; | |
95 | default: | |
96 | return 0; | |
97 | } | |
98 | } | |
99 | ||
100 | static void jzfb_free_gpio_pins(struct jzfb *jzfb) | |
101 | { | |
102 | jz_gpio_bulk_free(jz_slcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb)); | |
103 | if (jzfb->pdata->lcd_type & (1 << 6)) { | |
104 | /* serial */ | |
105 | jz_gpio_bulk_free(&jz_slcd_data_pins[15], 1); | |
106 | } else { | |
107 | /* parallel */ | |
108 | jz_gpio_bulk_free(jz_slcd_data_pins, | |
109 | jzfb_num_data_pins(jzfb)); | |
110 | } | |
111 | } | |
112 | ||
113 | static int jzfb_setcolreg(unsigned regno, unsigned red, unsigned green, | |
114 | unsigned blue, unsigned transp, struct fb_info *fb) | |
115 | { | |
116 | if (regno >= 16) | |
117 | return -EINVAL; | |
118 | ||
119 | red = (red * ((1 << fb->var.red.length ) - 1)) / ((1 << 16) - 1); | |
120 | green = (green * ((1 << fb->var.green.length) - 1)) / ((1 << 16) - 1); | |
121 | blue = (blue * ((1 << fb->var.blue.length ) - 1)) / ((1 << 16) - 1); | |
122 | ||
123 | ((uint32_t *)fb->pseudo_palette)[regno] = | |
124 | (red << fb->var.red.offset ) | | |
125 | (green << fb->var.green.offset) | | |
126 | (blue << fb->var.blue.offset ); | |
127 | ||
128 | return 0; | |
129 | } | |
130 | ||
131 | static int jzfb_get_controller_bpp(struct jzfb *jzfb) | |
132 | { | |
133 | switch (jzfb->pdata->bpp) { | |
134 | case 18: | |
135 | case 24: | |
136 | return 32; | |
137 | case 15: | |
138 | return 16; | |
139 | default: | |
140 | return jzfb->pdata->bpp; | |
141 | } | |
142 | } | |
143 | ||
144 | static struct fb_videomode *jzfb_get_mode(struct jzfb *jzfb, struct fb_var_screeninfo *var) | |
145 | { | |
146 | size_t i; | |
147 | struct fb_videomode *mode = jzfb->pdata->modes; | |
148 | ||
149 | for (i = 0; i < jzfb->pdata->num_modes; ++i, ++mode) { | |
150 | if (mode->xres == var->xres && mode->yres == var->yres) | |
151 | return mode; | |
152 | } | |
153 | ||
154 | return NULL; | |
155 | } | |
156 | ||
157 | static int jzfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb) | |
158 | { | |
159 | struct jzfb *jzfb = fb->par; | |
160 | struct fb_videomode *mode; | |
161 | ||
162 | if (var->bits_per_pixel != jzfb_get_controller_bpp(jzfb) && | |
163 | var->bits_per_pixel != jzfb->pdata->bpp) | |
164 | return -EINVAL; | |
165 | ||
166 | mode = jzfb_get_mode(jzfb, var); | |
167 | if (mode == NULL) | |
168 | return -EINVAL; | |
169 | ||
170 | fb_videomode_to_var(var, mode); | |
171 | ||
172 | /* Reserve space for double buffering. */ | |
173 | var->yres_virtual = var->yres * 2; | |
174 | ||
175 | switch (jzfb->pdata->bpp) { | |
176 | case 8: | |
177 | break; | |
178 | case 15: | |
179 | var->red.offset = 10; | |
180 | var->red.length = 5; | |
181 | var->green.offset = 5; | |
182 | var->green.length = 5; | |
183 | var->blue.offset = 0; | |
184 | var->blue.length = 5; | |
185 | break; | |
186 | case 16: | |
187 | var->red.offset = 11; | |
188 | var->red.length = 5; | |
189 | var->green.offset = 5; | |
190 | var->green.length = 6; | |
191 | var->blue.offset = 0; | |
192 | var->blue.length = 5; | |
193 | break; | |
194 | case 18: | |
195 | var->red.offset = 16; | |
196 | var->red.length = 6; | |
197 | var->green.offset = 8; | |
198 | var->green.length = 6; | |
199 | var->blue.offset = 0; | |
200 | var->blue.length = 6; | |
201 | var->bits_per_pixel = 32; | |
202 | break; | |
203 | case 32: | |
204 | case 24: | |
205 | var->transp.offset = 24; | |
206 | var->transp.length = 8; | |
207 | var->red.offset = 16; | |
208 | var->red.length = 8; | |
209 | var->green.offset = 8; | |
210 | var->green.length = 8; | |
211 | var->blue.offset = 0; | |
212 | var->blue.length = 8; | |
213 | var->bits_per_pixel = 32; | |
214 | break; | |
215 | default: | |
216 | break; | |
217 | } | |
218 | ||
219 | return 0; | |
220 | } | |
221 | ||
222 | static void jzfb_disable_dma(struct jzfb *jzfb) | |
223 | { | |
224 | jz4740_dma_disable(jzfb->dma); | |
225 | while (readb(jzfb->base + JZ_REG_SLCD_STATE) & SLCD_STATE_BUSY); | |
226 | writeb(readb(jzfb->base + JZ_REG_SLCD_CTRL) & ~SLCD_CTRL_DMA_EN, | |
227 | jzfb->base + JZ_REG_SLCD_CTRL); | |
228 | } | |
229 | ||
230 | static struct jz4740_dma_config jzfb_slcd_dma_config = { | |
231 | .src_width = JZ4740_DMA_WIDTH_32BIT, | |
232 | .dst_width = JZ4740_DMA_WIDTH_16BIT, | |
233 | .transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE, | |
234 | .request_type = JZ4740_DMA_TYPE_SLCD, | |
235 | .flags = JZ4740_DMA_SRC_AUTOINC, | |
236 | .mode = JZ4740_DMA_MODE_BLOCK, | |
237 | }; | |
238 | ||
239 | static void jzfb_upload_frame_dma(struct jzfb *jzfb) | |
240 | { | |
241 | struct fb_info *fb = jzfb->fb; | |
242 | struct fb_videomode *mode = fb->mode; | |
243 | __u32 bytes_per_line = fb->fix.line_length; | |
244 | ||
245 | jz4740_dma_set_src_addr(jzfb->dma, jzfb->vidmem_phys + | |
246 | bytes_per_line * fb->var.yoffset); | |
247 | jz4740_dma_set_dst_addr(jzfb->dma, | |
248 | CPHYSADDR(jzfb->base + JZ_REG_SLCD_FIFO)); | |
249 | jz4740_dma_set_transfer_count(jzfb->dma, bytes_per_line * mode->yres); | |
250 | ||
251 | while (readb(jzfb->base + JZ_REG_SLCD_STATE) & SLCD_STATE_BUSY); | |
252 | writeb(readb(jzfb->base + JZ_REG_SLCD_CTRL) | SLCD_CTRL_DMA_EN, | |
253 | jzfb->base + JZ_REG_SLCD_CTRL); | |
254 | jz4740_dma_enable(jzfb->dma); | |
255 | } | |
256 | ||
257 | static void jzfb_upload_frame_cpu(struct jzfb *jzfb) | |
258 | { | |
259 | const int num_pixels = jzfb->fb->mode->xres * jzfb->fb->mode->yres; | |
260 | uint16_t *p = jzfb->vidmem; | |
261 | int i; | |
262 | ||
263 | jzfb_disable_dma(jzfb); | |
264 | for (i = 0; i < num_pixels; i++) { | |
265 | uint16_t rgb = *p++; | |
266 | while (readb(jzfb->base + JZ_REG_SLCD_STATE) & SLCD_STATE_BUSY); | |
267 | writel(SLCD_DATA_RS_DATA | rgb, jzfb->base + JZ_REG_SLCD_DATA); | |
268 | } | |
269 | } | |
270 | ||
271 | static void jzfb_refresh_work(struct work_struct *work) | |
272 | { | |
273 | struct jzfb *jzfb = container_of(work, struct jzfb, refresh_work.work); | |
274 | ||
275 | mutex_lock(&jzfb->lock); | |
276 | if (jzfb->is_enabled) { | |
277 | if (1) { | |
278 | jzfb_upload_frame_dma(jzfb); | |
279 | /* The DMA complete callback will reschedule. */ | |
280 | } else { | |
281 | jzfb_upload_frame_cpu(jzfb); | |
282 | schedule_delayed_work(&jzfb->refresh_work, HZ / 10); | |
283 | } | |
284 | } | |
285 | mutex_unlock(&jzfb->lock); | |
286 | } | |
287 | ||
288 | static void jzfb_refresh_work_complete( | |
289 | struct jz4740_dma_chan *dma, int res, void *dev) | |
290 | { | |
291 | struct jzfb *jzfb = dev_get_drvdata(dev); | |
292 | // TODO: Stick to refresh rate in mode description. | |
293 | int interval = HZ / 60; | |
294 | ||
295 | schedule_delayed_work(&jzfb->refresh_work, interval); | |
296 | } | |
297 | ||
298 | static int jzfb_set_par(struct fb_info *info) | |
299 | { | |
300 | struct jzfb *jzfb = info->par; | |
301 | struct fb_var_screeninfo *var = &info->var; | |
302 | struct fb_videomode *mode; | |
303 | uint16_t slcd_cfg; | |
304 | ||
305 | mode = jzfb_get_mode(jzfb, var); | |
306 | if (mode == NULL) | |
307 | return -EINVAL; | |
308 | ||
309 | info->mode = mode; | |
310 | ||
311 | slcd_cfg = SLCD_CFG_BURST_8_WORD; | |
312 | /* command size */ | |
313 | slcd_cfg |= (jzfb->pdata->lcd_type & 3) << SLCD_CFG_CWIDTH_BIT; | |
314 | /* data size */ | |
315 | if (jzfb->pdata->lcd_type & (1 << 6)) { | |
316 | /* serial */ | |
317 | unsigned int num_bits; | |
318 | switch (jzfb->pdata->lcd_type) { | |
319 | case JZ_LCD_TYPE_SMART_SERIAL_8_BIT: | |
320 | slcd_cfg |= SLCD_CFG_DWIDTH_8_x1; | |
321 | num_bits = 8; | |
322 | break; | |
323 | case JZ_LCD_TYPE_SMART_SERIAL_16_BIT: | |
324 | slcd_cfg |= SLCD_CFG_DWIDTH_16; | |
325 | num_bits = 16; | |
326 | break; | |
327 | case JZ_LCD_TYPE_SMART_SERIAL_18_BIT: | |
328 | slcd_cfg |= SLCD_CFG_DWIDTH_18; | |
329 | num_bits = 18; | |
330 | break; | |
331 | default: | |
332 | num_bits = 0; | |
333 | break; | |
334 | } | |
335 | if (num_bits != jzfb->pdata->bpp) { | |
336 | dev_err(&jzfb->pdev->dev, | |
337 | "Data size (%d) does not match bpp (%d)\n", | |
338 | num_bits, jzfb->pdata->bpp); | |
339 | } | |
340 | slcd_cfg |= SLCD_CFG_TYPE_SERIAL; | |
341 | } else { | |
342 | /* parallel */ | |
343 | switch (jzfb->pdata->bpp) { | |
344 | case 8: | |
345 | slcd_cfg |= SLCD_CFG_DWIDTH_8_x1; | |
346 | break; | |
347 | case 15: | |
348 | case 16: | |
349 | switch (jzfb->pdata->lcd_type) { | |
350 | case JZ_LCD_TYPE_SMART_PARALLEL_8_BIT: | |
351 | slcd_cfg |= SLCD_CFG_DWIDTH_8_x2; | |
352 | break; | |
353 | default: | |
354 | slcd_cfg |= SLCD_CFG_DWIDTH_16; | |
355 | break; | |
356 | } | |
357 | break; | |
358 | case 18: | |
359 | switch (jzfb->pdata->lcd_type) { | |
360 | case JZ_LCD_TYPE_SMART_PARALLEL_8_BIT: | |
361 | slcd_cfg |= SLCD_CFG_DWIDTH_8_x3; | |
362 | break; | |
363 | case JZ_LCD_TYPE_SMART_PARALLEL_16_BIT: | |
364 | slcd_cfg |= SLCD_CFG_DWIDTH_9_x2; | |
365 | break; | |
366 | case JZ_LCD_TYPE_SMART_PARALLEL_18_BIT: | |
367 | slcd_cfg |= SLCD_CFG_DWIDTH_18; | |
368 | break; | |
369 | default: | |
370 | break; | |
371 | } | |
372 | break; | |
373 | case 24: | |
374 | slcd_cfg |= SLCD_CFG_DWIDTH_8_x3; | |
375 | break; | |
376 | default: | |
377 | dev_err(&jzfb->pdev->dev, | |
378 | "Unsupported value for bpp: %d\n", | |
379 | jzfb->pdata->bpp); | |
380 | } | |
381 | slcd_cfg |= SLCD_CFG_TYPE_PARALLEL; | |
382 | } | |
383 | if (!jzfb->pdata->chip_select_active_low) | |
384 | slcd_cfg |= SLCD_CFG_CS_ACTIVE_HIGH; | |
385 | if (!jzfb->pdata->register_select_active_low) | |
386 | slcd_cfg |= SLCD_CFG_RS_CMD_HIGH; | |
387 | if (!jzfb->pdata->pixclk_falling_edge) | |
388 | slcd_cfg |= SLCD_CFG_CLK_ACTIVE_RISING; | |
389 | ||
390 | #if 0 | |
391 | // TODO(MtH): Compute rate from refresh or vice versa. | |
392 | if (mode->pixclock) { | |
393 | rate = PICOS2KHZ(mode->pixclock) * 1000; | |
394 | mode->refresh = rate / vt / ht; | |
395 | } else { | |
396 | if (jzfb->pdata->lcd_type == JZ_LCD_TYPE_8BIT_SERIAL) | |
397 | rate = mode->refresh * (vt + 2 * mode->xres) * ht; | |
398 | else | |
399 | rate = mode->refresh * vt * ht; | |
400 | ||
401 | mode->pixclock = KHZ2PICOS(rate / 1000); | |
402 | } | |
403 | #endif | |
404 | ||
405 | mutex_lock(&jzfb->lock); | |
406 | if (!jzfb->is_enabled) | |
407 | clk_enable(jzfb->ldclk); | |
408 | ||
409 | // TODO(MtH): We should not change config while DMA might be running. | |
410 | writew(slcd_cfg, jzfb->base + JZ_REG_SLCD_CFG); | |
411 | ||
412 | if (!jzfb->is_enabled) | |
413 | clk_disable(jzfb->ldclk); | |
414 | mutex_unlock(&jzfb->lock); | |
415 | ||
416 | // TODO(MtH): Use maximum transfer speed that panel can handle. | |
417 | // ILI9325 can do 10 MHz. | |
418 | clk_set_rate(jzfb->lpclk, 12000000); | |
419 | clk_set_rate(jzfb->ldclk, 42000000); | |
420 | ||
421 | return 0; | |
422 | } | |
423 | ||
424 | static void jzfb_enable(struct jzfb *jzfb) | |
425 | { | |
426 | uint32_t ctrl; | |
427 | ||
428 | clk_enable(jzfb->ldclk); | |
429 | ||
430 | jz_gpio_bulk_resume(jz_slcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb)); | |
431 | if (jzfb->pdata->lcd_type & (1 << 6)) { | |
432 | /* serial */ | |
433 | jz_gpio_bulk_resume(&jz_slcd_data_pins[15], 1); | |
434 | } else { | |
435 | /* parallel */ | |
436 | jz_gpio_bulk_resume(jz_slcd_data_pins, | |
437 | jzfb_num_data_pins(jzfb)); | |
438 | } | |
439 | jzfb_disable_dma(jzfb); | |
440 | jzfb->panel->enable(jzfb); | |
441 | ||
442 | ctrl = readl(jzfb->base + JZ_REG_LCD_CTRL); | |
443 | ctrl |= JZ_LCD_CTRL_ENABLE; | |
444 | ctrl &= ~JZ_LCD_CTRL_DISABLE; | |
445 | writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL); | |
446 | ||
447 | schedule_delayed_work(&jzfb->refresh_work, 0); | |
448 | } | |
449 | ||
450 | static void jzfb_disable(struct jzfb *jzfb) | |
451 | { | |
452 | /* It is safe but wasteful to call refresh_work() while disabled. */ | |
453 | cancel_delayed_work(&jzfb->refresh_work); | |
454 | ||
455 | /* Abort any DMA transfer that might be in progress and allow direct | |
456 | writes to the panel. */ | |
457 | jzfb_disable_dma(jzfb); | |
458 | ||
459 | jzfb->panel->disable(jzfb); | |
460 | jz_gpio_bulk_suspend(jz_slcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb)); | |
461 | if (jzfb->pdata->lcd_type & (1 << 6)) { | |
462 | /* serial */ | |
463 | jz_gpio_bulk_suspend(&jz_slcd_data_pins[15], 1); | |
464 | } else { | |
465 | /* parallel */ | |
466 | jz_gpio_bulk_suspend(jz_slcd_data_pins, | |
467 | jzfb_num_data_pins(jzfb)); | |
468 | } | |
469 | ||
470 | clk_disable(jzfb->ldclk); | |
471 | } | |
472 | ||
473 | static int jzfb_blank(int blank_mode, struct fb_info *info) | |
474 | { | |
475 | struct jzfb* jzfb = info->par; | |
476 | int ret = 0; | |
477 | int new_enabled = (blank_mode == FB_BLANK_UNBLANK); | |
478 | ||
479 | mutex_lock(&jzfb->lock); | |
480 | if (new_enabled) { | |
481 | if (!jzfb->is_enabled) | |
482 | jzfb_enable(jzfb); | |
483 | } else { | |
484 | if (jzfb->is_enabled) { | |
485 | /* No sleep in TV-out mode. */ | |
486 | if (readl(jzfb->base + JZ_REG_LCD_CFG) & JZ_LCD_CFG_SLCD) | |
487 | jzfb_disable(jzfb); | |
488 | else | |
489 | ret = -EBUSY; | |
490 | } | |
491 | } | |
492 | if (!ret) | |
493 | jzfb->is_enabled = new_enabled; | |
494 | mutex_unlock(&jzfb->lock); | |
495 | ||
496 | return ret; | |
497 | } | |
498 | ||
499 | static int jzfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) | |
500 | { | |
501 | info->var.yoffset = var->yoffset; | |
502 | return 0; | |
503 | } | |
504 | ||
505 | static int jzfb_alloc_devmem(struct jzfb *jzfb) | |
506 | { | |
507 | int max_framesize = 0; | |
508 | struct fb_videomode *mode = jzfb->pdata->modes; | |
509 | void *page; | |
510 | int i; | |
511 | ||
512 | for (i = 0; i < jzfb->pdata->num_modes; ++mode, ++i) { | |
513 | if (max_framesize < mode->xres * mode->yres) | |
514 | max_framesize = mode->xres * mode->yres; | |
515 | } | |
516 | ||
517 | max_framesize *= jzfb_get_controller_bpp(jzfb) >> 3; | |
518 | ||
519 | jzfb->framedesc = dma_alloc_coherent(&jzfb->pdev->dev, | |
520 | sizeof(*jzfb->framedesc), | |
521 | &jzfb->framedesc_phys, GFP_KERNEL); | |
522 | ||
523 | if (!jzfb->framedesc) | |
524 | return -ENOMEM; | |
525 | ||
526 | /* reserve memory for two frames to allow double buffering */ | |
527 | jzfb->vidmem_size = PAGE_ALIGN(max_framesize * 2); | |
528 | jzfb->vidmem = dma_alloc_coherent(&jzfb->pdev->dev, | |
529 | jzfb->vidmem_size, | |
530 | &jzfb->vidmem_phys, GFP_KERNEL); | |
531 | ||
532 | if (!jzfb->vidmem) | |
533 | goto err_free_framedesc; | |
534 | ||
535 | for (page = jzfb->vidmem; | |
536 | page < jzfb->vidmem + PAGE_ALIGN(jzfb->vidmem_size); | |
537 | page += PAGE_SIZE) { | |
538 | SetPageReserved(virt_to_page(page)); | |
539 | } | |
540 | ||
541 | jzfb->framedesc->next = jzfb->framedesc_phys; | |
542 | jzfb->framedesc->addr = jzfb->vidmem_phys; | |
543 | jzfb->framedesc->id = 0xdeafbead; | |
544 | jzfb->framedesc->cmd = 0; | |
545 | jzfb->framedesc->cmd |= max_framesize / 4; | |
546 | ||
547 | return 0; | |
548 | ||
549 | err_free_framedesc: | |
550 | dma_free_coherent(&jzfb->pdev->dev, sizeof(*jzfb->framedesc), | |
551 | jzfb->framedesc, jzfb->framedesc_phys); | |
552 | return -ENOMEM; | |
553 | } | |
554 | ||
555 | static void jzfb_free_devmem(struct jzfb *jzfb) | |
556 | { | |
557 | dma_free_coherent(&jzfb->pdev->dev, jzfb->vidmem_size, | |
558 | jzfb->vidmem, jzfb->vidmem_phys); | |
559 | dma_free_coherent(&jzfb->pdev->dev, sizeof(*jzfb->framedesc), | |
560 | jzfb->framedesc, jzfb->framedesc_phys); | |
561 | } | |
562 | ||
563 | #include "jz4740_lcd.h" | |
564 | ||
565 | #define FBIOA320TVOUT 0x46F0 | |
566 | #define FB_A320TV_OFF 0 | |
567 | #define FB_A320TV_NTSC 1 | |
568 | #define FB_A320TV_PAL 2 | |
569 | ||
570 | static void jzfb_tv_out(struct jzfb *jzfb, unsigned int mode) | |
571 | { | |
572 | int blank = jzfb->is_enabled ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; | |
573 | struct fb_event event = { | |
574 | .info = jzfb->fb, | |
575 | .data = &blank, | |
576 | }; | |
577 | ||
578 | printk("A320 TV out: %d\n", mode); | |
579 | ||
580 | if (mode != FB_A320TV_OFF) { | |
581 | cancel_delayed_work(&jzfb->refresh_work); | |
582 | /* Abort any DMA transfer that might be in progress and | |
583 | allow direct writes to the panel. */ | |
584 | jzfb_disable_dma(jzfb); | |
585 | jzfb->panel->disable(jzfb); | |
586 | ||
587 | /* set up LCD controller for TV output */ | |
588 | ||
589 | writel(JZ_LCD_CFG_HSYNC_ACTIVE_LOW | | |
590 | JZ_LCD_CFG_VSYNC_ACTIVE_LOW, | |
591 | jzfb->base + JZ_REG_LCD_CFG); | |
592 | ||
593 | /* V-Sync pulse end position */ | |
594 | writel(10, jzfb->base + JZ_REG_LCD_VSYNC); | |
595 | ||
596 | if (mode == FB_A320TV_PAL) { | |
597 | /* PAL */ | |
598 | /* H-Sync pulse start position */ | |
599 | writel(125, jzfb->base + JZ_REG_LCD_HSYNC); | |
600 | /* virtual area size */ | |
601 | writel(0x036c0112, jzfb->base + JZ_REG_LCD_VAT); | |
602 | /* horizontal start/end point */ | |
603 | writel(0x02240364, jzfb->base + JZ_REG_LCD_DAH); | |
604 | /* vertical start/end point */ | |
605 | writel(0x1b010b, jzfb->base + JZ_REG_LCD_DAV); | |
606 | } | |
607 | else { | |
608 | /* NTSC */ | |
609 | writel(0x3c, jzfb->base + JZ_REG_LCD_HSYNC); | |
610 | writel(0x02e00110, jzfb->base + JZ_REG_LCD_VAT); | |
611 | writel(0x019902d9, jzfb->base + JZ_REG_LCD_DAH); | |
612 | writel(0x1d010d, jzfb->base + JZ_REG_LCD_DAV); | |
613 | } | |
614 | writel(0, jzfb->base + JZ_REG_LCD_PS); | |
615 | writel(0, jzfb->base + JZ_REG_LCD_CLS); | |
616 | writel(0, jzfb->base + JZ_REG_LCD_SPL); | |
617 | writel(0, jzfb->base + JZ_REG_LCD_REV); | |
618 | /* reset status register */ | |
619 | writel(0, jzfb->base + JZ_REG_LCD_STATE); | |
620 | ||
621 | /* tell LCDC about the frame descriptor address */ | |
622 | writel(jzfb->framedesc_phys, jzfb->base + JZ_REG_LCD_DA0); | |
623 | ||
624 | writel(JZ_LCD_CTRL_BURST_16 | JZ_LCD_CTRL_ENABLE | | |
625 | JZ_LCD_CTRL_BPP_15_16, | |
626 | jzfb->base + JZ_REG_LCD_CTRL); | |
627 | } | |
628 | else { | |
629 | /* disable LCD controller and re-enable SLCD */ | |
630 | writel(JZ_LCD_CFG_SLCD, jzfb->base + JZ_REG_LCD_CFG); | |
631 | jzfb->panel->enable(jzfb); | |
632 | schedule_delayed_work(&jzfb->refresh_work, 0); | |
633 | } | |
634 | ||
635 | /* reaffirm the current blanking state, to trigger a backlight update */ | |
636 | fb_notifier_call_chain(FB_EVENT_BLANK, &event); | |
637 | } | |
638 | ||
639 | static int jzfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) | |
640 | { | |
641 | struct jzfb *jzfb = info->par; | |
642 | switch (cmd) { | |
643 | case FBIOA320TVOUT: | |
644 | /* No TV-out mode while sleeping. */ | |
645 | if (!jzfb->is_enabled) | |
646 | return -EBUSY; | |
647 | ||
648 | jzfb_tv_out(jzfb, arg); | |
649 | break; | |
650 | default: | |
651 | return -EINVAL; | |
652 | } | |
653 | return 0; | |
654 | } | |
655 | ||
656 | static struct fb_ops jzfb_ops = { | |
657 | .owner = THIS_MODULE, | |
658 | .fb_check_var = jzfb_check_var, | |
659 | .fb_set_par = jzfb_set_par, | |
660 | .fb_setcolreg = jzfb_setcolreg, | |
661 | .fb_blank = jzfb_blank, | |
662 | .fb_pan_display = jzfb_pan_display, | |
663 | .fb_fillrect = sys_fillrect, | |
664 | .fb_copyarea = sys_copyarea, | |
665 | .fb_imageblit = sys_imageblit, | |
666 | .fb_ioctl = jzfb_ioctl, | |
667 | }; | |
668 | ||
669 | static int __devinit jzfb_probe(struct platform_device *pdev) | |
670 | { | |
671 | int ret; | |
672 | struct jzfb *jzfb; | |
673 | struct fb_info *fb; | |
674 | struct jz4740_fb_platform_data *pdata = pdev->dev.platform_data; | |
675 | struct resource *mem; | |
676 | ||
677 | if (!pdata) { | |
678 | dev_err(&pdev->dev, "Missing platform data\n"); | |
679 | return -ENOENT; | |
680 | } | |
681 | ||
682 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
683 | ||
684 | if (!mem) { | |
685 | dev_err(&pdev->dev, "Failed to get register memory resource\n"); | |
686 | return -ENOENT; | |
687 | } | |
688 | ||
689 | mem = request_mem_region(mem->start, resource_size(mem), pdev->name); | |
690 | ||
691 | if (!mem) { | |
692 | dev_err(&pdev->dev, "Failed to request register memory region\n"); | |
693 | return -EBUSY; | |
694 | } | |
695 | ||
696 | fb = framebuffer_alloc(sizeof(struct jzfb), &pdev->dev); | |
697 | ||
698 | if (!fb) { | |
699 | dev_err(&pdev->dev, "Failed to allocate framebuffer device\n"); | |
700 | ret = -ENOMEM; | |
701 | goto err_release_mem_region; | |
702 | } | |
703 | ||
704 | fb->fbops = &jzfb_ops; | |
705 | fb->flags = FBINFO_DEFAULT; | |
706 | ||
707 | jzfb = fb->par; | |
708 | jzfb->pdev = pdev; | |
709 | jzfb->pdata = pdata; | |
710 | jzfb->mem = mem; | |
711 | ||
712 | jzfb->dma = jz4740_dma_request(&pdev->dev, dev_name(&pdev->dev)); | |
713 | if (!jzfb->dma) { | |
714 | dev_err(&pdev->dev, "Failed to get DMA channel\n"); | |
715 | ret = -EBUSY; | |
716 | goto err_framebuffer_release; | |
717 | } | |
718 | jz4740_dma_configure(jzfb->dma, &jzfb_slcd_dma_config); | |
719 | jz4740_dma_set_complete_cb(jzfb->dma, &jzfb_refresh_work_complete); | |
720 | ||
721 | jzfb->ldclk = clk_get(&pdev->dev, "lcd"); | |
722 | if (IS_ERR(jzfb->ldclk)) { | |
723 | ret = PTR_ERR(jzfb->ldclk); | |
724 | dev_err(&pdev->dev, "Failed to get lcd clock: %d\n", ret); | |
725 | goto err_free_dma; | |
726 | } | |
727 | ||
728 | jzfb->lpclk = clk_get(&pdev->dev, "lcd_pclk"); | |
729 | if (IS_ERR(jzfb->lpclk)) { | |
730 | ret = PTR_ERR(jzfb->lpclk); | |
731 | dev_err(&pdev->dev, "Failed to get lcd pixel clock: %d\n", ret); | |
732 | goto err_put_ldclk; | |
733 | } | |
734 | ||
735 | jzfb->base = ioremap(mem->start, resource_size(mem)); | |
736 | ||
737 | if (!jzfb->base) { | |
738 | dev_err(&pdev->dev, "Failed to ioremap register memory region\n"); | |
739 | ret = -EBUSY; | |
740 | goto err_put_lpclk; | |
741 | } | |
742 | ||
743 | platform_set_drvdata(pdev, jzfb); | |
744 | ||
745 | fb_videomode_to_modelist(pdata->modes, pdata->num_modes, | |
746 | &fb->modelist); | |
747 | fb->mode = pdata->modes; | |
748 | ||
749 | fb_videomode_to_var(&fb->var, fb->mode); | |
750 | fb->var.bits_per_pixel = pdata->bpp; | |
751 | jzfb_check_var(&fb->var, fb); | |
752 | ||
753 | ret = jzfb_alloc_devmem(jzfb); | |
754 | if (ret) { | |
755 | dev_err(&pdev->dev, "Failed to allocate video memory\n"); | |
756 | goto err_iounmap; | |
757 | } | |
758 | ||
759 | fb->fix = jzfb_fix; | |
760 | fb->fix.line_length = fb->var.bits_per_pixel * fb->var.xres / 8; | |
761 | fb->fix.mmio_start = mem->start; | |
762 | fb->fix.mmio_len = resource_size(mem); | |
763 | fb->fix.smem_start = jzfb->vidmem_phys; | |
764 | fb->fix.smem_len = fb->fix.line_length * fb->var.yres_virtual; | |
765 | fb->screen_base = jzfb->vidmem; | |
766 | fb->pseudo_palette = jzfb->pseudo_palette; | |
767 | ||
768 | fb_alloc_cmap(&fb->cmap, 256, 0); | |
769 | ||
770 | mutex_init(&jzfb->lock); | |
771 | ||
772 | clk_enable(jzfb->ldclk); | |
773 | jzfb->is_enabled = 1; | |
774 | ||
775 | writel(JZ_LCD_CFG_SLCD, jzfb->base + JZ_REG_LCD_CFG); | |
776 | writeb(0, jzfb->base + JZ_REG_SLCD_CTRL); | |
777 | ||
778 | jzfb_set_par(fb); | |
779 | ||
780 | jz_gpio_bulk_request(jz_slcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb)); | |
781 | if (jzfb->pdata->lcd_type & (1 << 6)) { | |
782 | /* serial */ | |
783 | jz_gpio_bulk_request(&jz_slcd_data_pins[15], 1); | |
784 | } else { | |
785 | /* parallel */ | |
786 | jz_gpio_bulk_request(jz_slcd_data_pins, | |
787 | jzfb_num_data_pins(jzfb)); | |
788 | } | |
789 | ||
790 | jzfb->panel = jz_slcd_panels_probe(jzfb); | |
791 | if (!jzfb->panel) { | |
792 | dev_err(&pdev->dev, "Failed to find panel driver\n"); | |
793 | ret = -ENOENT; | |
794 | goto err_free_devmem; | |
795 | } | |
796 | jzfb_disable_dma(jzfb); | |
797 | jzfb->panel->init(jzfb); | |
798 | jzfb->panel->enable(jzfb); | |
799 | ||
800 | ret = register_framebuffer(fb); | |
801 | if (ret) { | |
802 | dev_err(&pdev->dev, "Failed to register framebuffer: %d\n", ret); | |
803 | goto err_free_panel; | |
804 | } | |
805 | ||
806 | jzfb->fb = fb; | |
807 | ||
808 | INIT_DELAYED_WORK(&jzfb->refresh_work, jzfb_refresh_work); | |
809 | schedule_delayed_work(&jzfb->refresh_work, 0); | |
810 | ||
811 | return 0; | |
812 | ||
813 | err_free_panel: | |
814 | jzfb->panel->exit(jzfb); | |
815 | err_free_devmem: | |
816 | jzfb_free_gpio_pins(jzfb); | |
817 | ||
818 | fb_dealloc_cmap(&fb->cmap); | |
819 | jzfb_free_devmem(jzfb); | |
820 | err_iounmap: | |
821 | iounmap(jzfb->base); | |
822 | err_put_lpclk: | |
823 | clk_put(jzfb->lpclk); | |
824 | err_put_ldclk: | |
825 | clk_put(jzfb->ldclk); | |
826 | err_free_dma: | |
827 | jz4740_dma_free(jzfb->dma); | |
828 | err_framebuffer_release: | |
829 | framebuffer_release(fb); | |
830 | err_release_mem_region: | |
831 | release_mem_region(mem->start, resource_size(mem)); | |
832 | return ret; | |
833 | } | |
834 | ||
835 | static int __devexit jzfb_remove(struct platform_device *pdev) | |
836 | { | |
837 | struct jzfb *jzfb = platform_get_drvdata(pdev); | |
838 | ||
839 | jzfb_blank(FB_BLANK_POWERDOWN, jzfb->fb); | |
840 | ||
841 | /* Blanking will prevent future refreshes from behind scheduled. | |
842 | Now wait for a possible refresh in progress to finish. */ | |
843 | cancel_delayed_work_sync(&jzfb->refresh_work); | |
844 | ||
845 | jzfb->panel->exit(jzfb); | |
846 | ||
847 | jzfb_free_gpio_pins(jzfb); | |
848 | ||
849 | jz4740_dma_free(jzfb->dma); | |
850 | ||
851 | iounmap(jzfb->base); | |
852 | release_mem_region(jzfb->mem->start, resource_size(jzfb->mem)); | |
853 | ||
854 | fb_dealloc_cmap(&jzfb->fb->cmap); | |
855 | jzfb_free_devmem(jzfb); | |
856 | ||
857 | platform_set_drvdata(pdev, NULL); | |
858 | ||
859 | clk_put(jzfb->lpclk); | |
860 | clk_put(jzfb->ldclk); | |
861 | ||
862 | framebuffer_release(jzfb->fb); | |
863 | ||
864 | return 0; | |
865 | } | |
866 | ||
867 | #ifdef CONFIG_PM | |
868 | ||
869 | static int jzfb_suspend(struct device *dev) | |
870 | { | |
871 | struct jzfb *jzfb = dev_get_drvdata(dev); | |
872 | ||
873 | console_lock(); | |
874 | fb_set_suspend(jzfb->fb, 1); | |
875 | console_unlock(); | |
876 | ||
877 | mutex_lock(&jzfb->lock); | |
878 | if (jzfb->is_enabled) | |
879 | jzfb_disable(jzfb); | |
880 | mutex_unlock(&jzfb->lock); | |
881 | ||
882 | return 0; | |
883 | } | |
884 | ||
885 | static int jzfb_resume(struct device *dev) | |
886 | { | |
887 | struct jzfb *jzfb = dev_get_drvdata(dev); | |
888 | clk_enable(jzfb->ldclk); | |
889 | ||
890 | mutex_lock(&jzfb->lock); | |
891 | if (jzfb->is_enabled) | |
892 | jzfb_enable(jzfb); | |
893 | mutex_unlock(&jzfb->lock); | |
894 | ||
895 | console_lock(); | |
896 | fb_set_suspend(jzfb->fb, 0); | |
897 | console_unlock(); | |
898 | ||
899 | return 0; | |
900 | } | |
901 | ||
902 | static const struct dev_pm_ops jzfb_pm_ops = { | |
903 | .suspend = jzfb_suspend, | |
904 | .resume = jzfb_resume, | |
905 | .poweroff = jzfb_suspend, | |
906 | .restore = jzfb_resume, | |
907 | }; | |
908 | ||
909 | #define JZFB_PM_OPS (&jzfb_pm_ops) | |
910 | ||
911 | #else | |
912 | #define JZFB_PM_OPS NULL | |
913 | #endif | |
914 | ||
915 | static struct platform_driver jzfb_driver = { | |
916 | .probe = jzfb_probe, | |
917 | .remove = __devexit_p(jzfb_remove), | |
918 | .driver = { | |
919 | .name = "jz4740-fb", | |
920 | .pm = JZFB_PM_OPS, | |
921 | }, | |
922 | }; | |
923 | ||
924 | static int __init jzfb_init(void) | |
925 | { | |
926 | return platform_driver_register(&jzfb_driver); | |
927 | } | |
928 | module_init(jzfb_init); | |
929 | ||
930 | static void __exit jzfb_exit(void) | |
931 | { | |
932 | platform_driver_unregister(&jzfb_driver); | |
933 | } | |
934 | module_exit(jzfb_exit); | |
935 | ||
936 | MODULE_LICENSE("GPL"); | |
937 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>, Maarten ter Huurne <maarten@treewalker.org>"); | |
938 | MODULE_DESCRIPTION("JZ4740 SoC SLCD framebuffer driver"); | |
939 | MODULE_ALIAS("platform:jz4740-fb"); |
drivers/video/jz4740_slcd_panels.c | ||
---|---|---|
1 | /* | |
2 | * linux/drivers/video/jz4740_slcd_panels.c | |
3 | * -- LCD panel definitions for Ingenic On-Chip SLCD frame buffer device | |
4 | * | |
5 | * Copyright (C) 2005-2007, Ingenic Semiconductor Inc. | |
6 | * Copyright (C) 2009, Ignacio Garcia Perez <iggarpe@gmail.com> | |
7 | * Copyright (C) 2010, Maarten ter Huurne <maarten@treewalker.org> | |
8 | * Copyright (C) 2011, ChinaChip | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License version 2 as | |
12 | * published by the Free Software Foundation. | |
13 | * | |
14 | */ | |
15 | ||
16 | #include <asm/io.h> | |
17 | #include <asm/mach-jz4740/gpio.h> | |
18 | #include <asm/mach-jz4740/jz4740_fb.h> | |
19 | #include <linux/delay.h> | |
20 | #include <linux/gpio.h> | |
21 | #include <linux/kernel.h> | |
22 | #include <linux/platform_device.h> | |
23 | ||
24 | #include "jz4740_slcd.h" | |
25 | ||
26 | /* Send a command without data. */ | |
27 | static void send_panel_command(struct jzfb *jzfb, u32 cmd) { | |
28 | u16 slcd_cfg = readw(jzfb->base + JZ_REG_SLCD_CFG); | |
29 | switch (slcd_cfg & SLCD_CFG_CWIDTH_MASK) { | |
30 | case SLCD_CFG_CWIDTH_8BIT: | |
31 | while (readb(jzfb->base + JZ_REG_SLCD_STATE) & SLCD_STATE_BUSY); | |
32 | writel(SLCD_DATA_RS_COMMAND | ((cmd&0xff00) >> 8), jzfb->base + JZ_REG_SLCD_DATA); | |
33 | while (readb(jzfb->base + JZ_REG_SLCD_STATE) & SLCD_STATE_BUSY); | |
34 | writel(SLCD_DATA_RS_COMMAND | ((cmd&0xff) >> 0), jzfb->base + JZ_REG_SLCD_DATA); | |
35 | break; | |
36 | case SLCD_CFG_CWIDTH_16BIT: | |
37 | while (readb(jzfb->base + JZ_REG_SLCD_STATE) & SLCD_STATE_BUSY); | |
38 | writel(SLCD_DATA_RS_COMMAND | (cmd&0xffff), jzfb->base + JZ_REG_SLCD_DATA); | |
39 | break; | |
40 | case SLCD_CFG_CWIDTH_18BIT: | |
41 | while (readb(jzfb->base + JZ_REG_SLCD_STATE) & SLCD_STATE_BUSY); | |
42 | writel(SLCD_DATA_RS_COMMAND | ((cmd&0xff00) << 2) | ((cmd&0xff) << 1), jzfb->base + JZ_REG_SLCD_DATA); | |
43 | break; | |
44 | default: | |
45 | break; | |
46 | } | |
47 | } | |
48 | ||
49 | /* Send data without command. */ | |
50 | static void send_panel_data(struct jzfb *jzfb, u32 data) | |
51 | { | |
52 | u16 slcd_cfg = readw(jzfb->base + JZ_REG_SLCD_CFG); | |
53 | switch (slcd_cfg & SLCD_CFG_DWIDTH_MASK) { | |
54 | case SLCD_CFG_DWIDTH_18: | |
55 | while (readb(jzfb->base + JZ_REG_SLCD_STATE) & SLCD_STATE_BUSY); | |
56 | data = ((data & 0xff) << 1) | ((data & 0xff00) << 2); | |
57 | writel(SLCD_DATA_RS_DATA | ((data<<6)&0xfc0000)|((data<<4)&0xfc00) | ((data<<2)&0xfc), jzfb->base + JZ_REG_SLCD_DATA); | |
58 | break; | |
59 | case SLCD_CFG_DWIDTH_16: | |
60 | while (readb(jzfb->base + JZ_REG_SLCD_STATE) & SLCD_STATE_BUSY); | |
61 | writel(SLCD_DATA_RS_DATA | (data&0xffff), jzfb->base + JZ_REG_SLCD_DATA); | |
62 | break; | |
63 | case SLCD_CFG_DWIDTH_9_x2: | |
64 | data = ((data & 0xff) << 1) | ((data & 0xff00) << 2); | |
65 | data = ((data << 6) & 0xfc0000) | ((data << 4) & 0xfc00) | ((data << 2) & 0xfc); | |
66 | while (readb(jzfb->base + JZ_REG_SLCD_STATE) & SLCD_STATE_BUSY); | |
67 | writel(SLCD_DATA_RS_DATA | data, jzfb->base + JZ_REG_SLCD_DATA); | |
68 | break; | |
69 | default: | |
70 | while (readb(jzfb->base + JZ_REG_SLCD_STATE) & SLCD_STATE_BUSY); | |
71 | writel(SLCD_DATA_RS_DATA | (data&0xffff), jzfb->base + JZ_REG_SLCD_DATA); | |
72 | break; | |
73 | } | |
74 | } | |
75 | ||
76 | /* Send command and data. */ | |
77 | static void set_panel_reg(struct jzfb *jzfb, u32 cmd, u32 data) | |
78 | { | |
79 | send_panel_command(jzfb, cmd); | |
80 | send_panel_data(jzfb, data); | |
81 | } | |
82 | ||
83 | #ifdef CONFIG_JZ_SLCD_ILI9325 | |
84 | ||
85 | // TODO(MtH): GPIO assignments belong in the board definition, since two | |
86 | // boards using the same panel controller could still use different | |
87 | // GPIO assignments. | |
88 | // TODO(MtH): CS mismatch: B17 (A320) vs C20 (standard). | |
89 | #define ILI9325_GPIO_CS_N JZ_GPIO_PORTB(17) /* Chip select */ | |
90 | #define ILI9325_GPIO_RESET_N JZ_GPIO_PORTB(18) /* LCD reset */ | |
91 | ||
92 | static int ili9325_init(struct jzfb *jzfb) | |
93 | { | |
94 | struct device *dev = &jzfb->pdev->dev; | |
95 | int ret; | |
96 | ||
97 | ret = gpio_request(ILI9325_GPIO_CS_N, dev_name(dev)); | |
98 | if (ret) | |
99 | goto err_cs; | |
100 | gpio_direction_output(ILI9325_GPIO_CS_N, 1); | |
101 | ||
102 | ret = gpio_request(ILI9325_GPIO_RESET_N, dev_name(dev)); | |
103 | if (ret) | |
104 | goto err_reset; | |
105 | gpio_direction_output(ILI9325_GPIO_RESET_N, 0); | |
106 | ||
107 | mdelay(100); | |
108 | return 0; | |
109 | ||
110 | err_reset: | |
111 | gpio_free(ILI9325_GPIO_CS_N); | |
112 | err_cs: | |
113 | dev_err(dev, "Could not reserve GPIO pins for ILI9325 panel driver\n"); | |
114 | return ret; | |
115 | } | |
116 | ||
117 | static void ili9325_exit(struct jzfb *jzfb) | |
118 | { | |
119 | gpio_free(ILI9325_GPIO_CS_N); | |
120 | gpio_free(ILI9325_GPIO_RESET_N); | |
121 | } | |
122 | ||
123 | static void ili9325_enable(struct jzfb *jzfb) | |
124 | { | |
125 | /* RESET pulse */ | |
126 | gpio_set_value(ILI9325_GPIO_RESET_N, 0); | |
127 | mdelay(10); | |
128 | gpio_set_value(ILI9325_GPIO_RESET_N, 1); | |
129 | mdelay(50); | |
130 | ||
131 | /* Enable chip select */ | |
132 | gpio_set_value(ILI9325_GPIO_CS_N, 0); | |
133 | ||
134 | /* Black magic */ | |
135 | set_panel_reg(jzfb, 0xE3, 0x3008); | |
136 | set_panel_reg(jzfb, 0xE7, 0x0012); | |
137 | set_panel_reg(jzfb, 0xEF, 0x1231); | |
138 | set_panel_reg(jzfb, 0x01, 0x0100); | |
139 | set_panel_reg(jzfb, 0x02, 0x0700); | |
140 | set_panel_reg(jzfb, 0x03, 0x1098); | |
141 | set_panel_reg(jzfb, 0x04, 0x0000); | |
142 | set_panel_reg(jzfb, 0x08, 0x0207); | |
143 | set_panel_reg(jzfb, 0x09, 0x0000); | |
144 | set_panel_reg(jzfb, 0x0A, 0x0000); | |
145 | set_panel_reg(jzfb, 0x0C, 0x0000); | |
146 | set_panel_reg(jzfb, 0x0D, 0x0000); | |
147 | set_panel_reg(jzfb, 0x0F, 0x0000); | |
148 | set_panel_reg(jzfb, 0x10, 0x0000); | |
149 | set_panel_reg(jzfb, 0x11, 0x0007); | |
150 | set_panel_reg(jzfb, 0x12, 0x0000); | |
151 | set_panel_reg(jzfb, 0x13, 0x0000); | |
152 | mdelay(200); | |
153 | set_panel_reg(jzfb, 0x10, 0x1290); | |
154 | set_panel_reg(jzfb, 0x11, 0x0227); | |
155 | mdelay(50); | |
156 | set_panel_reg(jzfb, 0x12, 0x001B); | |
157 | mdelay(50); | |
158 | set_panel_reg(jzfb, 0x13, 0x0500); | |
159 | set_panel_reg(jzfb, 0x29, 0x000C); | |
160 | set_panel_reg(jzfb, 0x2B, 0x000D); | |
161 | mdelay(50); | |
162 | set_panel_reg(jzfb, 0x20, 0x0000); | |
163 | set_panel_reg(jzfb, 0x21, 0x0000); | |
164 | set_panel_reg(jzfb, 0x30, 0x0000); | |
165 | set_panel_reg(jzfb, 0x31, 0x0204); | |
166 | set_panel_reg(jzfb, 0x32, 0x0200); | |
167 | set_panel_reg(jzfb, 0x35, 0x0007); | |
168 | set_panel_reg(jzfb, 0x36, 0x1404); | |
169 | set_panel_reg(jzfb, 0x37, 0x0705); | |
170 | set_panel_reg(jzfb, 0x38, 0x0305); | |
171 | set_panel_reg(jzfb, 0x39, 0x0707); | |
172 | set_panel_reg(jzfb, 0x3C, 0x0701); | |
173 | set_panel_reg(jzfb, 0x3D, 0x000E); | |
174 | set_panel_reg(jzfb, 0x50, 0x0000); | |
175 | set_panel_reg(jzfb, 0x51, 0x00EF); | |
176 | set_panel_reg(jzfb, 0x52, 0x0000); | |
177 | set_panel_reg(jzfb, 0x53, 0x013F); | |
178 | set_panel_reg(jzfb, 0x60, 0xA700); | |
179 | set_panel_reg(jzfb, 0x61, 0x0001); | |
180 | set_panel_reg(jzfb, 0x6A, 0x0000); | |
181 | set_panel_reg(jzfb, 0x80, 0x0000); | |
182 | set_panel_reg(jzfb, 0x81, 0x0000); | |
183 | set_panel_reg(jzfb, 0x82, 0x0000); | |
184 | set_panel_reg(jzfb, 0x83, 0x0000); | |
185 | set_panel_reg(jzfb, 0x84, 0x0000); | |
186 | set_panel_reg(jzfb, 0x85, 0x0000); | |
187 | set_panel_reg(jzfb, 0x90, 0x0010); | |
188 | set_panel_reg(jzfb, 0x92, 0x0600); | |
189 | mdelay(50); | |
190 | set_panel_reg(jzfb, 0x07, 0x0133); | |
191 | mdelay(50); | |
192 | send_panel_command(jzfb, 0x22); | |
193 | } | |
194 | ||
195 | /* TODO(IGP): make sure LCD power consumption is low in these conditions */ | |
196 | static void ili9325_disable(struct jzfb *jzfb) | |
197 | { | |
198 | /* Keep chip select disabled */ | |
199 | gpio_set_value(ILI9325_GPIO_CS_N, 1); | |
200 | /* Keep RESET active */ | |
201 | gpio_set_value(ILI9325_GPIO_RESET_N, 0); | |
202 | } | |
203 | ||
204 | #endif | |
205 | ||
206 | #ifdef CONFIG_JZ_SLCD_ILI9331 | |
207 | ||
208 | #define ILI9331_GPIO_CS_N JZ_GPIO_PORTB(17) /* Chip select */ | |
209 | #define ILI9331_GPIO_RESET_N JZ_GPIO_PORTB(18) /* LCD reset */ | |
210 | ||
211 | static int ili9331_init(struct jzfb *jzfb) | |
212 | { | |
213 | struct device *dev = &jzfb->pdev->dev; | |
214 | int ret; | |
215 | ||
216 | ret = gpio_request(ILI9331_GPIO_CS_N, dev_name(dev)); | |
217 | if (ret) | |
218 | goto err_cs; | |
219 | gpio_direction_output(ILI9331_GPIO_CS_N, 1); | |
220 | ||
221 | ret = gpio_request(ILI9331_GPIO_RESET_N, dev_name(dev)); | |
222 | if (ret) | |
223 | goto err_reset; | |
224 | gpio_direction_output(ILI9331_GPIO_RESET_N, 0); | |
225 | ||
226 | mdelay(100); | |
227 | return 0; | |
228 | ||
229 | err_reset: | |
230 | gpio_free(ILI9331_GPIO_CS_N); | |
231 | err_cs: | |
232 | dev_err(dev, "Could not reserve GPIO pins for ILI9331 panel driver\n"); | |
233 | return ret; | |
234 | } | |
235 | ||
236 | static void ili9331_exit(struct jzfb *jzfb) | |
237 | { | |
238 | gpio_free(ILI9331_GPIO_CS_N); | |
239 | gpio_free(ILI9331_GPIO_RESET_N); | |
240 | } | |
241 | ||
242 | static void ili9331_enable(struct jzfb *jzfb) | |
243 | { | |
244 | /* RESET pulse */ | |
245 | gpio_set_value(ILI9331_GPIO_RESET_N, 0); | |
246 | mdelay(10); | |
247 | gpio_set_value(ILI9331_GPIO_RESET_N, 1); | |
248 | mdelay(50); | |
249 | ||
250 | /* Enable chip select */ | |
251 | gpio_set_value(ILI9331_GPIO_CS_N, 0); | |
252 | ||
253 | /* Black magic */ | |
254 | set_panel_reg(jzfb, 0xE7, 0x1014); | |
255 | set_panel_reg(jzfb, 0x01, 0x0000); | |
256 | set_panel_reg(jzfb, 0x02, 0x0200); | |
257 | set_panel_reg(jzfb, 0x03, 0x1048); | |
258 | set_panel_reg(jzfb, 0x08, 0x0202); | |
259 | set_panel_reg(jzfb, 0x09, 0x0000); | |
260 | set_panel_reg(jzfb, 0x0A, 0x0000); | |
261 | set_panel_reg(jzfb, 0x0C, 0x0000); | |
262 | set_panel_reg(jzfb, 0x0D, 0x0000); | |
263 | set_panel_reg(jzfb, 0x0F, 0x0000); | |
264 | set_panel_reg(jzfb, 0x10, 0x0000); | |
265 | set_panel_reg(jzfb, 0x11, 0x0007); | |
266 | set_panel_reg(jzfb, 0x12, 0x0000); | |
267 | set_panel_reg(jzfb, 0x13, 0x0000); | |
268 | mdelay(100); | |
269 | set_panel_reg(jzfb, 0x10, 0x1690); | |
270 | set_panel_reg(jzfb, 0x11, 0x0224); | |
271 | mdelay(50); | |
272 | set_panel_reg(jzfb, 0x12, 0x001F); | |
273 | mdelay(50); | |
274 | set_panel_reg(jzfb, 0x13, 0x0500); | |
275 | set_panel_reg(jzfb, 0x29, 0x000C); | |
276 | set_panel_reg(jzfb, 0x2B, 0x000D); | |
277 | mdelay(50); | |
278 | set_panel_reg(jzfb, 0x30, 0x0000); | |
279 | set_panel_reg(jzfb, 0x31, 0x0106); | |
280 | set_panel_reg(jzfb, 0x32, 0x0000); | |
281 | set_panel_reg(jzfb, 0x35, 0x0204); | |
282 | set_panel_reg(jzfb, 0x36, 0x160A); | |
283 | set_panel_reg(jzfb, 0x37, 0x0707); | |
284 | set_panel_reg(jzfb, 0x38, 0x0106); | |
285 | set_panel_reg(jzfb, 0x39, 0x0706); | |
286 | set_panel_reg(jzfb, 0x3C, 0x0402); | |
287 | set_panel_reg(jzfb, 0x3D, 0x0C0F); | |
288 | set_panel_reg(jzfb, 0x50, 0x0000); | |
289 | set_panel_reg(jzfb, 0x51, 0x00EF); | |
290 | set_panel_reg(jzfb, 0x52, 0x0000); | |
291 | set_panel_reg(jzfb, 0x53, 0x013F); | |
292 | set_panel_reg(jzfb, 0x20, 0x0000); | |
293 | set_panel_reg(jzfb, 0x21, 0x0000); | |
294 | set_panel_reg(jzfb, 0x60, 0x2700); | |
295 | set_panel_reg(jzfb, 0x61, 0x0001); | |
296 | set_panel_reg(jzfb, 0x6A, 0x0000); | |
297 | set_panel_reg(jzfb, 0x80, 0x0000); | |
298 | set_panel_reg(jzfb, 0x81, 0x0000); | |
299 | set_panel_reg(jzfb, 0x82, 0x0000); | |
300 | set_panel_reg(jzfb, 0x83, 0x0000); | |
301 | set_panel_reg(jzfb, 0x84, 0x0000); | |
302 | set_panel_reg(jzfb, 0x85, 0x0000); | |
303 | set_panel_reg(jzfb, 0x20, 0x00EF); | |
304 | set_panel_reg(jzfb, 0x21, 0x0190); | |
305 | set_panel_reg(jzfb, 0x90, 0x0010); | |
306 | set_panel_reg(jzfb, 0x92, 0x0600); | |
307 | set_panel_reg(jzfb, 0x07, 0x0133); | |
308 | send_panel_command(jzfb, 0x22); | |
309 | } | |
310 | ||
311 | /* TODO(IGP): make sure LCD power consumption is low in these conditions */ | |
312 | static void ili9331_disable(struct jzfb *jzfb) | |
313 | { | |
314 | /* Keep chip select disabled */ | |
315 | gpio_set_value(ILI9331_GPIO_CS_N, 1); | |
316 | /* Keep RESET active */ | |
317 | gpio_set_value(ILI9331_GPIO_RESET_N, 0); | |
318 | } | |
319 | ||
320 | #endif | |
321 | ||
322 | #ifdef CONFIG_JZ_SLCD_ILI9338 | |
323 | ||
324 | #define ILI9338_GPIO_CS_N JZ_GPIO_PORTB(17) /* Chip select */ | |
325 | #define ILI9338_GPIO_RESET_N JZ_GPIO_PORTB(18) /* LCD reset */ | |
326 | ||
327 | static int ili9338_init(struct jzfb *jzfb) | |
328 | { | |
329 | struct device *dev = &jzfb->pdev->dev; | |
330 | int ret; | |
331 | ||
332 | ret = gpio_request(ILI9338_GPIO_CS_N, dev_name(dev)); | |
333 | if (ret) | |
334 | goto err_cs; | |
335 | gpio_direction_output(ILI9338_GPIO_CS_N, 1); | |
336 | ||
337 | ret = gpio_request(ILI9338_GPIO_RESET_N, dev_name(dev)); | |
338 | if (ret) | |
339 | goto err_reset; | |
340 | gpio_direction_output(ILI9338_GPIO_RESET_N, 0); | |
341 | ||
342 | mdelay(100); | |
343 | return 0; | |
344 | ||
345 | err_reset: | |
346 | gpio_free(ILI9338_GPIO_CS_N); | |
347 | err_cs: | |
348 | dev_err(dev, "Could not reserve GPIO pins for ILI9338 panel driver\n"); | |
349 | return ret; | |
350 | } | |
351 | ||
352 | static void ili9338_exit(struct jzfb *jzfb) | |
353 | { | |
354 | gpio_free(ILI9338_GPIO_CS_N); | |
355 | gpio_free(ILI9338_GPIO_RESET_N); | |
356 | } | |
357 | ||
358 | static void ili9338_enable(struct jzfb *jzfb) | |
359 | { | |
360 | /* RESET pulse */ | |
361 | gpio_set_value(ILI9338_GPIO_RESET_N, 0); | |
362 | mdelay(10); | |
363 | gpio_set_value(ILI9338_GPIO_RESET_N, 1); | |
364 | mdelay(50); | |
365 | ||
366 | /* Enable chip select */ | |
367 | gpio_set_value(ILI9338_GPIO_CS_N, 0); | |
368 | ||
369 | /* Black magic */ | |
370 | send_panel_command(jzfb, 0x11); | |
371 | mdelay(100); | |
372 | ||
373 | send_panel_command(jzfb, 0xCB); | |
374 | send_panel_data(jzfb, 0x01); | |
375 | ||
376 | send_panel_command(jzfb, 0xC0); | |
377 | send_panel_data(jzfb, 0x26); | |
378 | send_panel_data(jzfb, 0x01); | |
379 | send_panel_command(jzfb, 0xC1); | |
380 | send_panel_data(jzfb, 0x10); | |
381 | send_panel_command(jzfb, 0xC5); | |
382 | send_panel_data(jzfb, 0x10); | |
383 | send_panel_data(jzfb, 0x52); | |
384 | ||
385 | send_panel_command(jzfb, 0x26); | |
386 | send_panel_data(jzfb, 0x01); | |
387 | send_panel_command(jzfb, 0xE0); | |
388 | send_panel_data(jzfb, 0x10); | |
389 | send_panel_data(jzfb, 0x10); | |
390 | send_panel_data(jzfb, 0x10); | |
391 | send_panel_data(jzfb, 0x08); | |
392 | send_panel_data(jzfb, 0x0E); | |
393 | send_panel_data(jzfb, 0x06); | |
394 | send_panel_data(jzfb, 0x42); | |
395 | send_panel_data(jzfb, 0x28); | |
396 | send_panel_data(jzfb, 0x36); | |
397 | send_panel_data(jzfb, 0x03); | |
398 | send_panel_data(jzfb, 0x0E); | |
399 | send_panel_data(jzfb, 0x04); | |
400 | send_panel_data(jzfb, 0x13); | |
401 | send_panel_data(jzfb, 0x0E); | |
402 | send_panel_data(jzfb, 0x0C); | |
403 | send_panel_command(jzfb, 0XE1); | |
404 | send_panel_data(jzfb, 0x0C); | |
405 | send_panel_data(jzfb, 0x23); | |
406 | send_panel_data(jzfb, 0x26); | |
407 | send_panel_data(jzfb, 0x04); | |
408 | send_panel_data(jzfb, 0x0C); | |
409 | send_panel_data(jzfb, 0x04); | |
410 | send_panel_data(jzfb, 0x39); | |
411 | send_panel_data(jzfb, 0x24); | |
412 | send_panel_data(jzfb, 0x4B); | |
413 | send_panel_data(jzfb, 0x03); | |
414 | send_panel_data(jzfb, 0x0B); | |
415 | send_panel_data(jzfb, 0x0B); | |
416 | send_panel_data(jzfb, 0x33); | |
417 | send_panel_data(jzfb, 0x37); | |
418 | send_panel_data(jzfb, 0x0F); | |
419 | ||
420 | send_panel_command(jzfb, 0x2a); | |
421 | send_panel_data(jzfb, 0x00); | |
422 | send_panel_data(jzfb, 0x00); | |
423 | send_panel_data(jzfb, 0x01); | |
424 | send_panel_data(jzfb, 0x3f); | |
425 | ||
426 | send_panel_command(jzfb, 0x2b); | |
427 | send_panel_data(jzfb, 0x00); | |
428 | send_panel_data(jzfb, 0x00); | |
429 | send_panel_data(jzfb, 0x00); | |
430 | send_panel_data(jzfb, 0xef); | |
431 | ||
432 | send_panel_command(jzfb, 0x36); | |
433 | send_panel_data(jzfb, 0xe8); | |
434 | ||
435 | send_panel_command(jzfb, 0x3A); | |
436 | send_panel_data(jzfb, 0x05); | |
437 | ||
438 | send_panel_command(jzfb, 0x29); | |
439 | ||
440 | send_panel_command(jzfb, 0x2c); | |
441 | } | |
442 | ||
443 | /* TODO(IGP): make sure LCD power consumption is low in these conditions */ | |
444 | static void ili9338_disable(struct jzfb *jzfb) | |
445 | { | |
446 | /* Keep chip select disabled */ | |
447 | gpio_set_value(ILI9338_GPIO_CS_N, 1); | |
448 | /* Keep RESET active */ | |
449 | gpio_set_value(ILI9338_GPIO_RESET_N, 0); | |
450 | } | |
451 | ||
452 | #endif | |
453 | ||
454 | #ifdef CONFIG_JZ_SLCD_LGDP4551 | |
455 | ||
456 | #define LGDP4551_GPIO_CS_N JZ_GPIO_PORTC(18) /* Chip select */ | |
457 | #define LGDP4551_GPIO_RESET_N JZ_GPIO_PORTC(21) /* LCD reset */ | |
458 | ||
459 | /* Set the start address of screen, for example (0, 0) */ | |
460 | static void lgdp4551_set_addr(struct jzfb *jzfb, u16 x, u16 y) | |
461 | { | |
462 | set_panel_reg(jzfb, 0x20, x); | |
463 | udelay(1); | |
464 | set_panel_reg(jzfb, 0x21, y); | |
465 | udelay(1); | |
466 | send_panel_command(jzfb, 0x22); | |
467 | } | |
468 | ||
469 | static int lgdp4551_init(struct jzfb *jzfb) | |
470 | { | |
471 | struct device *dev = &jzfb->pdev->dev; | |
472 | int ret; | |
473 | ||
474 | ret = gpio_request(LGDP4551_GPIO_CS_N, dev_name(dev)); | |
475 | if (ret) | |
476 | goto err_cs; | |
477 | gpio_direction_output(LGDP4551_GPIO_CS_N, 0); | |
478 | ||
479 | ret = gpio_request(LGDP4551_GPIO_RESET_N, dev_name(dev)); | |
480 | if (ret) | |
481 | goto err_reset; | |
482 | gpio_direction_output(LGDP4551_GPIO_RESET_N, 1); | |
483 | ||
484 | mdelay(100); | |
485 | return 0; | |
486 | ||
487 | err_reset: | |
488 | gpio_free(LGDP4551_GPIO_CS_N); | |
489 | err_cs: | |
490 | dev_err(dev, "Could not reserve GPIO pins for LGDP4551 panel\n"); | |
491 | return ret; | |
492 | } | |
493 | ||
494 | static void lgdp4551_exit(struct jzfb *jzfb) | |
495 | { | |
496 | gpio_free(LGDP4551_GPIO_CS_N); | |
497 | gpio_free(LGDP4551_GPIO_RESET_N); | |
498 | } | |
499 | ||
500 | static void lgdp4551_enable(struct jzfb *jzfb) | |
501 | { | |
502 | /* RESET# */ | |
503 | gpio_set_value(LGDP4551_GPIO_RESET_N, 1); | |
504 | mdelay(10); | |
505 | gpio_set_value(LGDP4551_GPIO_RESET_N, 0); | |
506 | mdelay(10); | |
507 | gpio_set_value(LGDP4551_GPIO_RESET_N, 1); | |
508 | mdelay(100); | |
509 | set_panel_reg(jzfb, 0x0015, 0x0050); | |
510 | set_panel_reg(jzfb, 0x0011, 0x0000); | |
511 | set_panel_reg(jzfb, 0x0010, 0x3628); | |
512 | set_panel_reg(jzfb, 0x0012, 0x0002); | |
513 | set_panel_reg(jzfb, 0x0013, 0x0E47); | |
514 | udelay(100); | |
515 | set_panel_reg(jzfb, 0x0012, 0x0012); | |
516 | udelay(100); | |
517 | set_panel_reg(jzfb, 0x0010, 0x3620); | |
518 | set_panel_reg(jzfb, 0x0013, 0x2E47); | |
519 | udelay(50); | |
520 | set_panel_reg(jzfb, 0x0030, 0x0000); | |
521 | set_panel_reg(jzfb, 0x0031, 0x0502); | |
522 | set_panel_reg(jzfb, 0x0032, 0x0307); | |
523 | set_panel_reg(jzfb, 0x0033, 0x0304); | |
524 | set_panel_reg(jzfb, 0x0034, 0x0004); | |
525 | set_panel_reg(jzfb, 0x0035, 0x0401); | |
526 | set_panel_reg(jzfb, 0x0036, 0x0707); | |
527 | set_panel_reg(jzfb, 0x0037, 0x0303); | |
528 | set_panel_reg(jzfb, 0x0038, 0x1E02); | |
529 | set_panel_reg(jzfb, 0x0039, 0x1E02); | |
530 | set_panel_reg(jzfb, 0x0001, 0x0000); | |
531 | set_panel_reg(jzfb, 0x0002, 0x0300); | |
532 | if (jzfb->pdata->bpp == 16) | |
533 | set_panel_reg(jzfb, 0x0003, 0x10B8); /*8-bit system interface two transfers | |
534 | up:0x10B8 down:0x1088 left:0x1090 right:0x10a0*/ | |
535 | else if (jzfb->pdata->bpp == 32) | |
536 | set_panel_reg(jzfb, 0x0003, 0xD0B8);/*8-bit system interface three transfers,666 | |
537 | up:0xD0B8 down:0xD088 left:0xD090 right:0xD0A0*/ | |
538 | set_panel_reg(jzfb, 0x0008, 0x0204); | |
539 | set_panel_reg(jzfb, 0x000A, 0x0008); | |
540 | set_panel_reg(jzfb, 0x0060, 0x3100); | |
541 | set_panel_reg(jzfb, 0x0061, 0x0001); | |
542 | set_panel_reg(jzfb, 0x0090, 0x0052); | |
543 | set_panel_reg(jzfb, 0x0092, 0x000F); | |
544 | set_panel_reg(jzfb, 0x0093, 0x0001); | |
545 | set_panel_reg(jzfb, 0x009A, 0x0008); | |
546 | set_panel_reg(jzfb, 0x00A3, 0x0010); | |
547 | set_panel_reg(jzfb, 0x0050, 0x0000); | |
548 | set_panel_reg(jzfb, 0x0051, 0x00EF); | |
549 | set_panel_reg(jzfb, 0x0052, 0x0000); | |
550 | set_panel_reg(jzfb, 0x0053, 0x018F); | |
551 | /*===Display_On_Function=== */ | |
552 | set_panel_reg(jzfb, 0x0007, 0x0001); | |
553 | set_panel_reg(jzfb, 0x0007, 0x0021); | |
554 | set_panel_reg(jzfb, 0x0007, 0x0023); | |
555 | set_panel_reg(jzfb, 0x0007, 0x0033); | |
556 | set_panel_reg(jzfb, 0x0007, 0x0133); | |
557 | send_panel_command(jzfb, 0x0022); /* Write Data to GRAM. */ | |
558 | udelay(1); | |
559 | lgdp4551_set_addr(jzfb, 0, 0); | |
560 | mdelay(100); | |
561 | } | |
562 | ||
563 | static void lgdp4551_disable(struct jzfb *jzfb) | |
564 | { | |
565 | } | |
566 | ||
567 | #endif | |
568 | ||
569 | #ifdef CONFIG_JZ_SLCD_SPFD5420A | |
570 | ||
571 | #define SPFD5420A_GPIO_CS_N JZ_GPIO_PORTC(22) /* Chip select */ | |
572 | #define SPFD5420A_GPIO_RESET_N JZ_GPIO_PORTB(18) /* LCD reset */ | |
573 | #define SPFD5420A_GPIO_POWER_N JZ_GPIO_PORTD(0) /* Power off */ | |
574 | #define SPFD5420A_GPIO_FMARK_N JZ_GPIO_PORTD(1) /* fmark */ | |
575 | ||
576 | /* Set the start address of screen, for example (0, 0) */ | |
577 | static void spfd5420a_set_addr(struct jzfb *jzfb, u32 x, u32 y) | |
578 | { | |
579 | set_panel_reg(jzfb, 0x200, x); | |
580 | udelay(1); | |
581 | set_panel_reg(jzfb, 0x201, y); | |
582 | udelay(1); | |
583 | send_panel_command(jzfb, 0x202); | |
584 | } | |
585 | ||
586 | static int spfd5420a_init(struct jzfb *jzfb) | |
587 | { | |
588 | struct device *dev = &jzfb->pdev->dev; | |
589 | int ret; | |
590 | ||
591 | ret = gpio_request(SPFD5420A_GPIO_CS_N, dev_name(dev)); | |
592 | if (ret) | |
593 | goto err_cs; | |
594 | gpio_direction_output(SPFD5420A_GPIO_CS_N, 0); | |
595 | ||
596 | ret = gpio_request(SPFD5420A_GPIO_RESET_N, dev_name(dev)); | |
597 | if (ret) | |
598 | goto err_reset; | |
599 | gpio_direction_output(SPFD5420A_GPIO_RESET_N, 1); | |
600 | ||
601 | ret = gpio_request(SPFD5420A_GPIO_POWER_N, dev_name(dev)); | |
602 | if (ret) | |
603 | goto err_power; | |
604 | gpio_direction_output(SPFD5420A_GPIO_POWER_N, 0); | |
605 | ||
606 | mdelay(100); | |
607 | return 0; | |
608 | ||
609 | err_power: | |
610 | gpio_free(SPFD5420A_GPIO_RESET_N); | |
611 | err_reset: | |
612 | gpio_free(SPFD5420A_GPIO_CS_N); | |
613 | err_cs: | |
614 | dev_err(dev, "Could not reserve GPIO pins for SPFD5420A panel\n"); | |
615 | return ret; | |
616 | } | |
617 | ||
618 | static void spfd5420a_exit(struct jzfb *jzfb) | |
619 | { | |
620 | gpio_free(SPFD5420A_GPIO_CS_N); | |
621 | gpio_free(SPFD5420A_GPIO_RESET_N); | |
622 | gpio_free(SPFD5420A_GPIO_POWER_N); | |
623 | } | |
624 | ||
625 | static void spfd5420a_init_gamma(struct jzfb *jzfb) | |
626 | { | |
627 | set_panel_reg(jzfb, 0x0300, 0x0101); | |
628 | set_panel_reg(jzfb, 0x0301, 0x0b27); | |
629 | set_panel_reg(jzfb, 0x0302, 0x132a); | |
630 | set_panel_reg(jzfb, 0x0303, 0x2a13); | |
631 | set_panel_reg(jzfb, 0x0304, 0x270b); | |
632 | set_panel_reg(jzfb, 0x0305, 0x0101); | |
633 | set_panel_reg(jzfb, 0x0306, 0x1205); | |
634 | set_panel_reg(jzfb, 0x0307, 0x0512); | |
635 | set_panel_reg(jzfb, 0x0308, 0x0005); | |
636 | set_panel_reg(jzfb, 0x0309, 0x0003); | |
637 | set_panel_reg(jzfb, 0x030a, 0x0f04); | |
638 | set_panel_reg(jzfb, 0x030b, 0x0f00); | |
639 | set_panel_reg(jzfb, 0x030c, 0x000f); | |
640 | set_panel_reg(jzfb, 0x030d, 0x040f); | |
641 | set_panel_reg(jzfb, 0x030e, 0x0300); | |
642 | set_panel_reg(jzfb, 0x030f, 0x0500); | |
643 | /*** secorrect gamma2 ***/ | |
644 | set_panel_reg(jzfb, 0x0400, 0x3500); | |
645 | set_panel_reg(jzfb, 0x0401, 0x0001); | |
646 | set_panel_reg(jzfb, 0x0404, 0x0000); | |
647 | set_panel_reg(jzfb, 0x0500, 0x0000); | |
648 | set_panel_reg(jzfb, 0x0501, 0x0000); | |
649 | set_panel_reg(jzfb, 0x0502, 0x0000); | |
650 | set_panel_reg(jzfb, 0x0503, 0x0000); | |
651 | set_panel_reg(jzfb, 0x0504, 0x0000); | |
652 | set_panel_reg(jzfb, 0x0505, 0x0000); | |
653 | set_panel_reg(jzfb, 0x0600, 0x0000); | |
654 | set_panel_reg(jzfb, 0x0606, 0x0000); | |
655 | set_panel_reg(jzfb, 0x06f0, 0x0000); | |
656 | set_panel_reg(jzfb, 0x07f0, 0x5420); | |
657 | set_panel_reg(jzfb, 0x07f3, 0x288a); | |
658 | set_panel_reg(jzfb, 0x07f4, 0x0022); | |
659 | set_panel_reg(jzfb, 0x07f5, 0x0001); | |
660 | set_panel_reg(jzfb, 0x07f0, 0x0000); | |
661 | } | |
662 | ||
663 | static void spfd5420a_enable(struct jzfb *jzfb) | |
664 | { | |
665 | gpio_set_value(SPFD5420A_GPIO_RESET_N, 1); | |
666 | mdelay(10); | |
667 | gpio_set_value(SPFD5420A_GPIO_RESET_N, 0); | |
668 | mdelay(10); | |
669 | gpio_set_value(SPFD5420A_GPIO_RESET_N, 1); | |
670 | mdelay(100); | |
671 | if (jzfb->pdata->lcd_type == JZ_LCD_TYPE_SMART_PARALLEL_18_BIT) { | |
672 | set_panel_reg(jzfb, 0x0606, 0x0000); | |
673 | udelay(10); | |
674 | set_panel_reg(jzfb, 0x0007, 0x0001); | |
675 | udelay(10); | |
676 | set_panel_reg(jzfb, 0x0110, 0x0001); | |
677 | udelay(10); | |
678 | set_panel_reg(jzfb, 0x0100, 0x17b0); | |
679 | set_panel_reg(jzfb, 0x0101, 0x0147); | |
680 | set_panel_reg(jzfb, 0x0102, 0x019d); | |
681 | set_panel_reg(jzfb, 0x0103, 0x8600); | |
682 | set_panel_reg(jzfb, 0x0281, 0x0010); | |
683 | udelay(10); | |
684 | set_panel_reg(jzfb, 0x0102, 0x01bd); | |
685 | udelay(10); | |
686 | /************initial************/ | |
687 | set_panel_reg(jzfb, 0x0000, 0x0000); | |
688 | set_panel_reg(jzfb, 0x0001, 0x0000); | |
689 | set_panel_reg(jzfb, 0x0002, 0x0400); | |
690 | set_panel_reg(jzfb, 0x0003, 0x1288); /*up:0x1288 down:0x12B8 left:0x1290 right:0x12A0*/ | |
691 | set_panel_reg(jzfb, 0x0006, 0x0000); | |
692 | set_panel_reg(jzfb, 0x0008, 0x0503); | |
693 | set_panel_reg(jzfb, 0x0009, 0x0001); | |
694 | set_panel_reg(jzfb, 0x000b, 0x0010); | |
695 | set_panel_reg(jzfb, 0x000c, 0x0000); | |
696 | set_panel_reg(jzfb, 0x000f, 0x0000); | |
697 | set_panel_reg(jzfb, 0x0007, 0x0001); | |
698 | set_panel_reg(jzfb, 0x0010, 0x0010); | |
699 | set_panel_reg(jzfb, 0x0011, 0x0202); | |
700 | set_panel_reg(jzfb, 0x0012, 0x0300); | |
701 | set_panel_reg(jzfb, 0x0020, 0x021e); | |
702 | set_panel_reg(jzfb, 0x0021, 0x0202); | |
703 | set_panel_reg(jzfb, 0x0022, 0x0100); | |
704 | set_panel_reg(jzfb, 0x0090, 0x0000); | |
705 | set_panel_reg(jzfb, 0x0092, 0x0000); | |
706 | set_panel_reg(jzfb, 0x0100, 0x16b0); | |
707 | set_panel_reg(jzfb, 0x0101, 0x0147); | |
708 | set_panel_reg(jzfb, 0x0102, 0x01bd); | |
709 | set_panel_reg(jzfb, 0x0103, 0x2c00); | |
710 | set_panel_reg(jzfb, 0x0107, 0x0000); | |
711 | set_panel_reg(jzfb, 0x0110, 0x0001); | |
712 | set_panel_reg(jzfb, 0x0210, 0x0000); | |
713 | set_panel_reg(jzfb, 0x0211, 0x00ef); | |
714 | set_panel_reg(jzfb, 0x0212, 0x0000); | |
715 | set_panel_reg(jzfb, 0x0213, 0x018f); | |
716 | set_panel_reg(jzfb, 0x0280, 0x0000); | |
717 | set_panel_reg(jzfb, 0x0281, 0x0001); | |
718 | set_panel_reg(jzfb, 0x0282, 0x0000); | |
719 | spfd5420a_init_gamma(jzfb); | |
720 | set_panel_reg(jzfb, 0x0007, 0x0173); | |
721 | } else { | |
722 | set_panel_reg(jzfb, 0x0600, 0x0001); /*soft reset*/ | |
723 | mdelay(10); | |
724 | set_panel_reg(jzfb, 0x0600, 0x0000); /*soft reset*/ | |
725 | mdelay(10); | |
726 | set_panel_reg(jzfb, 0x0606, 0x0000); /*i80-i/F Endian Control*/ | |
727 | /*===User setting=== */ | |
728 | set_panel_reg(jzfb, 0x0001, 0x0000);/* Driver Output Control-----0x0100 SM(bit10) | 0x400*/ | |
729 | set_panel_reg(jzfb, 0x0002, 0x0100); /*LCD Driving Wave Control 0x0100 */ | |
730 | if (jzfb->pdata->bpp == 16) | |
731 | set_panel_reg(jzfb, 0x0003, 0x50A8);/*Entry Mode 0x1030*/ | |
732 | else /*bpp = 18*/ | |
733 | set_panel_reg(jzfb, 0x0003, 0x1010 | 0xC8); /*Entry Mode 0x1030*/ | |
734 | set_panel_reg(jzfb, 0x0006, 0x0000); /*Outline Sharpening Control*/ | |
735 | set_panel_reg(jzfb, 0x0008, 0x0808); /*Sets the number of lines for front/back porch period*/ | |
736 | set_panel_reg(jzfb, 0x0009, 0x0001); /*Display Control 3 */ | |
737 | set_panel_reg(jzfb, 0x000B, 0x0010); /*Low Power Control*/ | |
738 | set_panel_reg(jzfb, 0x000C, 0x0000); /*External Display Interface Control 1 0x0001 */ | |
739 | set_panel_reg(jzfb, 0x000F, 0x0000); /*External Display Interface Control 2 */ | |
740 | set_panel_reg(jzfb, 0x0400, 0xB104); /*Base Image Number of Line---GS(bit15) | 0x8000*/ | |
741 | set_panel_reg(jzfb, 0x0401, 0x0001); /*Base Image Display 0x0001*/ | |
742 | set_panel_reg(jzfb, 0x0404, 0x0000); /*Base Image Vertical Scroll Control 0x0000*/ | |
743 | set_panel_reg(jzfb, 0x0500, 0x0000); /*Partial Image 1: Display Position*/ | |
744 | set_panel_reg(jzfb, 0x0501, 0x0000); /*RAM Address (Start Line Address) */ | |
745 | set_panel_reg(jzfb, 0x0502, 0x018f); /*RAM Address (End Line Address) */ | |
746 | set_panel_reg(jzfb, 0x0503, 0x0000); /*Partial Image 2: Display Position RAM Address*/ | |
747 | set_panel_reg(jzfb, 0x0504, 0x0000); /*RAM Address (Start Line Address) */ | |
748 | set_panel_reg(jzfb, 0x0505, 0x0000); /*RAM Address (End Line Address)*/ | |
749 | /*Panel interface control===*/ | |
750 | set_panel_reg(jzfb, 0x0010, 0x0011); /*Division Ratio,Clocks per Line 14 */ | |
751 | mdelay(10); | |
752 | set_panel_reg(jzfb, 0x0011, 0x0202); /*Division Ratio,Clocks per Line*/ | |
753 | set_panel_reg(jzfb, 0x0012, 0x0300); /*Sets low power VCOM drive period. */ | |
754 | mdelay(10); | |
755 | set_panel_reg(jzfb, 0x0020, 0x021e); /*Panel Interface Control 4 */ | |
756 | set_panel_reg(jzfb, 0x0021, 0x0202); /*Panel Interface Control 5 */ | |
757 | set_panel_reg(jzfb, 0x0022, 0x0100); /*Panel Interface Control 6*/ | |
758 | set_panel_reg(jzfb, 0x0090, 0x0000); /*Frame Marker Control */ | |
759 | set_panel_reg(jzfb, 0x0092, 0x0000); /*MDDI Sub-display Control */ | |
760 | /*===Gamma setting=== */ | |
761 | set_panel_reg(jzfb, 0x0300, 0x0101); /*γ Control*/ | |
762 | set_panel_reg(jzfb, 0x0301, 0x0000); /*γ Control*/ | |
763 | set_panel_reg(jzfb, 0x0302, 0x0016); /*γ Control*/ | |
764 | set_panel_reg(jzfb, 0x0303, 0x2913); /*γ Control*/ | |
765 | set_panel_reg(jzfb, 0x0304, 0x260B); /*γ Control*/ | |
766 | set_panel_reg(jzfb, 0x0305, 0x0101); /*γ Control*/ | |
767 | set_panel_reg(jzfb, 0x0306, 0x1204); /*γ Control*/ | |
768 | set_panel_reg(jzfb, 0x0307, 0x0415); /*γ Control*/ | |
769 | set_panel_reg(jzfb, 0x0308, 0x0205); /*γ Control*/ | |
770 | set_panel_reg(jzfb, 0x0309, 0x0303); /*γ Control*/ | |
771 | set_panel_reg(jzfb, 0x030a, 0x0E05); /*γ Control*/ | |
772 | set_panel_reg(jzfb, 0x030b, 0x0D01); /*γ Control*/ | |
773 | set_panel_reg(jzfb, 0x030c, 0x010D); /*γ Control*/ | |
774 | set_panel_reg(jzfb, 0x030d, 0x050E); /*γ Control*/ | |
775 | set_panel_reg(jzfb, 0x030e, 0x0303); /*γ Control*/ | |
776 | set_panel_reg(jzfb, 0x030f, 0x0502); /*γ Control*/ | |
777 | /*===Power on sequence===*/ | |
778 | set_panel_reg(jzfb, 0x0007, 0x0001); /*Display Control 1*/ | |
779 | set_panel_reg(jzfb, 0x0110, 0x0001); /*Power supply startup enable bit*/ | |
780 | set_panel_reg(jzfb, 0x0112, 0x0060); /*Power Control 7*/ | |
781 | set_panel_reg(jzfb, 0x0100, 0x16B0); /*Power Control 1 */ | |
782 | set_panel_reg(jzfb, 0x0101, 0x0115); /*Power Control 2*/ | |
783 | set_panel_reg(jzfb, 0x0102, 0x0119); /*Starts VLOUT3,Sets the VREG1OUT.*/ | |
784 | mdelay(50); | |
785 | set_panel_reg(jzfb, 0x0103, 0x2E00); /*set the amplitude of VCOM*/ | |
786 | mdelay(50); | |
787 | set_panel_reg(jzfb, 0x0282, 0x0093); /*VCOMH voltage, alt: 0x008E, 0x0093*/ | |
788 | set_panel_reg(jzfb, 0x0281, 0x000A); /*Selects the factor of VREG1OUT to generate VCOMH. */ | |
789 | set_panel_reg(jzfb, 0x0102, 0x01BE); /*Starts VLOUT3,Sets the VREG1OUT.*/ | |
790 | mdelay(10); | |
791 | /*Address */ | |
792 | set_panel_reg(jzfb, 0x0210, 0x0000); /*Window Horizontal RAM Address Start*/ | |
793 | set_panel_reg(jzfb, 0x0211, 0x00ef); /*Window Horizontal RAM Address End*/ | |
794 | set_panel_reg(jzfb, 0x0212, 0x0000); /*Window Vertical RAM Address Start*/ | |
795 | set_panel_reg(jzfb, 0x0213, 0x018f); /*Window Vertical RAM Address End */ | |
796 | set_panel_reg(jzfb, 0x0200, 0x0000); /*RAM Address Set (Horizontal Address)*/ | |
797 | set_panel_reg(jzfb, 0x0201, 0x018f); /*RAM Address Set (Vertical Address)*/ | |
798 | /*===Display_On_Function===*/ | |
799 | set_panel_reg(jzfb, 0x0007, 0x0021); /*Display Control 1 */ | |
800 | mdelay(50); /*40*/ | |
801 | set_panel_reg(jzfb, 0x0007, 0x0061); /*Display Control 1 */ | |
802 | mdelay(50); /*100*/ | |
803 | set_panel_reg(jzfb, 0x0007, 0x0173); /*Display Control 1 */ | |
804 | mdelay(50); /*300*/ | |
805 | } | |
806 | send_panel_command(jzfb, 0x0202); /*Write Data to GRAM */ | |
807 | udelay(10); | |
808 | spfd5420a_set_addr(jzfb, 0, 0); | |
809 | udelay(100); | |
810 | } | |
811 | ||
812 | static void spfd5420a_disable(struct jzfb *jzfb) | |
813 | { | |
814 | } | |
815 | ||
816 | #endif | |
817 | ||
818 | static const struct jz_slcd_panel jz_slcd_panels[] = { | |
819 | #ifdef CONFIG_JZ_SLCD_ILI9325 | |
820 | { | |
821 | ili9325_init, ili9325_exit, | |
822 | ili9325_enable, ili9325_disable, | |
823 | }, | |
824 | #endif | |
825 | #ifdef CONFIG_JZ_SLCD_ILI9331 | |
826 | { | |
827 | ili9331_init, ili9331_exit, | |
828 | ili9331_enable, ili9331_disable, | |
829 | }, | |
830 | #endif | |
831 | #ifdef CONFIG_JZ_SLCD_ILI9338 | |
832 | { | |
833 | ili9338_init, ili9338_exit, | |
834 | ili9338_enable, ili9338_disable, | |
835 | }, | |
836 | #endif | |
837 | #ifdef CONFIG_JZ_SLCD_LGDP4551 | |
838 | { | |
839 | lgdp4551_init, lgdp4551_exit, | |
840 | lgdp4551_enable, lgdp4551_disable, | |
841 | }, | |
842 | #endif | |
843 | #ifdef CONFIG_JZ_SLCD_SPFD5420A | |
844 | { | |
845 | spfd5420a_init, spfd5420a_exit, | |
846 | spfd5420a_enable, spfd5420a_disable, | |
847 | }, | |
848 | #endif | |
849 | }; | |
850 | ||
851 | const struct jz_slcd_panel *jz_slcd_panels_probe(struct jzfb *jzfb) | |
852 | { | |
853 | switch (ARRAY_SIZE(jz_slcd_panels)) { | |
854 | case 0: | |
855 | return NULL; | |
856 | case 1: | |
857 | return &jz_slcd_panels[0]; | |
858 | default: | |
859 | dev_warn(&jzfb->pdev->dev, | |
860 | "SLCD panel selection not implemented yet; " | |
861 | "picking first panel\n"); | |
862 | return &jz_slcd_panels[0]; | |
863 | } | |
864 | } |
Branches:
ben-wpan
ben-wpan-stefan
5396a9238205f20f811ea57898980d3ca82df0b6
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9