diff options
author | Ryan Mallon <ryan@bluewatersys.com> | 2009-09-22 19:47:09 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-23 10:39:51 -0400 |
commit | c6012189a40d33213ead5d15769fab615443206f (patch) | |
tree | 56682b59b54f18f0134d373e309121f87a907297 | |
parent | d63870db3c41086d7f13ec8b41def4331db32327 (diff) |
ep93xx video driver platform support
Signed-off-by: Ryan Mallon <ryan@bluewatersys.com>
Acked-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Daniele Venzano <linux@brownhat.org>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: Krzysztof Helt <krzysztof.h1@poczta.fm>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | arch/arm/mach-ep93xx/clock.c | 88 | ||||
-rw-r--r-- | arch/arm/mach-ep93xx/core.c | 32 | ||||
-rw-r--r-- | arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-ep93xx/include/mach/fb.h | 56 | ||||
-rw-r--r-- | arch/arm/mach-ep93xx/include/mach/platform.h | 2 |
5 files changed, 183 insertions, 1 deletions
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c index 3dd0e2a23095..dda19cd76194 100644 --- a/arch/arm/mach-ep93xx/clock.c +++ b/arch/arm/mach-ep93xx/clock.c | |||
@@ -37,7 +37,7 @@ struct clk { | |||
37 | static unsigned long get_uart_rate(struct clk *clk); | 37 | static unsigned long get_uart_rate(struct clk *clk); |
38 | 38 | ||
39 | static int set_keytchclk_rate(struct clk *clk, unsigned long rate); | 39 | static int set_keytchclk_rate(struct clk *clk, unsigned long rate); |
40 | 40 | static int set_div_rate(struct clk *clk, unsigned long rate); | |
41 | 41 | ||
42 | static struct clk clk_uart1 = { | 42 | static struct clk clk_uart1 = { |
43 | .sw_locked = 1, | 43 | .sw_locked = 1, |
@@ -76,6 +76,13 @@ static struct clk clk_pwm = { | |||
76 | .rate = EP93XX_EXT_CLK_RATE, | 76 | .rate = EP93XX_EXT_CLK_RATE, |
77 | }; | 77 | }; |
78 | 78 | ||
79 | static struct clk clk_video = { | ||
80 | .sw_locked = 1, | ||
81 | .enable_reg = EP93XX_SYSCON_VIDCLKDIV, | ||
82 | .enable_mask = EP93XX_SYSCON_CLKDIV_ENABLE, | ||
83 | .set_rate = set_div_rate, | ||
84 | }; | ||
85 | |||
79 | /* DMA Clocks */ | 86 | /* DMA Clocks */ |
80 | static struct clk clk_m2p0 = { | 87 | static struct clk clk_m2p0 = { |
81 | .enable_reg = EP93XX_SYSCON_PWRCNT, | 88 | .enable_reg = EP93XX_SYSCON_PWRCNT, |
@@ -140,6 +147,7 @@ static struct clk_lookup clocks[] = { | |||
140 | INIT_CK(NULL, "pll2", &clk_pll2), | 147 | INIT_CK(NULL, "pll2", &clk_pll2), |
141 | INIT_CK("ep93xx-ohci", NULL, &clk_usb_host), | 148 | INIT_CK("ep93xx-ohci", NULL, &clk_usb_host), |
142 | INIT_CK("ep93xx-keypad", NULL, &clk_keypad), | 149 | INIT_CK("ep93xx-keypad", NULL, &clk_keypad), |
150 | INIT_CK("ep93xx-fb", NULL, &clk_video), | ||
143 | INIT_CK(NULL, "pwm_clk", &clk_pwm), | 151 | INIT_CK(NULL, "pwm_clk", &clk_pwm), |
144 | INIT_CK(NULL, "m2p0", &clk_m2p0), | 152 | INIT_CK(NULL, "m2p0", &clk_m2p0), |
145 | INIT_CK(NULL, "m2p1", &clk_m2p1), | 153 | INIT_CK(NULL, "m2p1", &clk_m2p1), |
@@ -236,6 +244,84 @@ static int set_keytchclk_rate(struct clk *clk, unsigned long rate) | |||
236 | return 0; | 244 | return 0; |
237 | } | 245 | } |
238 | 246 | ||
247 | static unsigned long calc_clk_div(unsigned long rate, int *psel, int *esel, | ||
248 | int *pdiv, int *div) | ||
249 | { | ||
250 | unsigned long max_rate, best_rate = 0, | ||
251 | actual_rate = 0, mclk_rate = 0, rate_err = -1; | ||
252 | int i, found = 0, __div = 0, __pdiv = 0; | ||
253 | |||
254 | /* Don't exceed the maximum rate */ | ||
255 | max_rate = max(max(clk_pll1.rate / 4, clk_pll2.rate / 4), | ||
256 | (unsigned long)EP93XX_EXT_CLK_RATE / 4); | ||
257 | rate = min(rate, max_rate); | ||
258 | |||
259 | /* | ||
260 | * Try the two pll's and the external clock | ||
261 | * Because the valid predividers are 2, 2.5 and 3, we multiply | ||
262 | * all the clocks by 2 to avoid floating point math. | ||
263 | * | ||
264 | * This is based on the algorithm in the ep93xx raster guide: | ||
265 | * http://be-a-maverick.com/en/pubs/appNote/AN269REV1.pdf | ||
266 | * | ||
267 | */ | ||
268 | for (i = 0; i < 3; i++) { | ||
269 | if (i == 0) | ||
270 | mclk_rate = EP93XX_EXT_CLK_RATE * 2; | ||
271 | else if (i == 1) | ||
272 | mclk_rate = clk_pll1.rate * 2; | ||
273 | else if (i == 2) | ||
274 | mclk_rate = clk_pll2.rate * 2; | ||
275 | |||
276 | /* Try each predivider value */ | ||
277 | for (__pdiv = 4; __pdiv <= 6; __pdiv++) { | ||
278 | __div = mclk_rate / (rate * __pdiv); | ||
279 | if (__div < 2 || __div > 127) | ||
280 | continue; | ||
281 | |||
282 | actual_rate = mclk_rate / (__pdiv * __div); | ||
283 | |||
284 | if (!found || abs(actual_rate - rate) < rate_err) { | ||
285 | *pdiv = __pdiv - 3; | ||
286 | *div = __div; | ||
287 | *psel = (i == 2); | ||
288 | *esel = (i != 0); | ||
289 | best_rate = actual_rate; | ||
290 | rate_err = abs(actual_rate - rate); | ||
291 | found = 1; | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | |||
296 | if (!found) | ||
297 | return 0; | ||
298 | |||
299 | return best_rate; | ||
300 | } | ||
301 | |||
302 | static int set_div_rate(struct clk *clk, unsigned long rate) | ||
303 | { | ||
304 | unsigned long actual_rate; | ||
305 | int psel = 0, esel = 0, pdiv = 0, div = 0; | ||
306 | u32 val; | ||
307 | |||
308 | actual_rate = calc_clk_div(rate, &psel, &esel, &pdiv, &div); | ||
309 | if (actual_rate == 0) | ||
310 | return -EINVAL; | ||
311 | clk->rate = actual_rate; | ||
312 | |||
313 | /* Clear the esel, psel, pdiv and div bits */ | ||
314 | val = __raw_readl(clk->enable_reg); | ||
315 | val &= ~0x7fff; | ||
316 | |||
317 | /* Set the new esel, psel, pdiv and div bits for the new clock rate */ | ||
318 | val |= (esel ? EP93XX_SYSCON_CLKDIV_ESEL : 0) | | ||
319 | (psel ? EP93XX_SYSCON_CLKDIV_PSEL : 0) | | ||
320 | (pdiv << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | div; | ||
321 | ep93xx_syscon_swlocked_write(val, clk->enable_reg); | ||
322 | return 0; | ||
323 | } | ||
324 | |||
239 | int clk_set_rate(struct clk *clk, unsigned long rate) | 325 | int clk_set_rate(struct clk *clk, unsigned long rate) |
240 | { | 326 | { |
241 | if (clk->set_rate) | 327 | if (clk->set_rate) |
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index 16b92c37ec99..f7ebed942f66 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/i2c-gpio.h> | 30 | #include <linux/i2c-gpio.h> |
31 | 31 | ||
32 | #include <mach/hardware.h> | 32 | #include <mach/hardware.h> |
33 | #include <mach/fb.h> | ||
33 | 34 | ||
34 | #include <asm/mach/map.h> | 35 | #include <asm/mach/map.h> |
35 | #include <asm/mach/time.h> | 36 | #include <asm/mach/time.h> |
@@ -682,6 +683,37 @@ void ep93xx_pwm_release_gpio(struct platform_device *pdev) | |||
682 | EXPORT_SYMBOL(ep93xx_pwm_release_gpio); | 683 | EXPORT_SYMBOL(ep93xx_pwm_release_gpio); |
683 | 684 | ||
684 | 685 | ||
686 | /************************************************************************* | ||
687 | * EP93xx video peripheral handling | ||
688 | *************************************************************************/ | ||
689 | static struct ep93xxfb_mach_info ep93xxfb_data; | ||
690 | |||
691 | static struct resource ep93xx_fb_resource[] = { | ||
692 | { | ||
693 | .start = EP93XX_RASTER_PHYS_BASE, | ||
694 | .end = EP93XX_RASTER_PHYS_BASE + 0x800 - 1, | ||
695 | .flags = IORESOURCE_MEM, | ||
696 | }, | ||
697 | }; | ||
698 | |||
699 | static struct platform_device ep93xx_fb_device = { | ||
700 | .name = "ep93xx-fb", | ||
701 | .id = -1, | ||
702 | .dev = { | ||
703 | .platform_data = &ep93xxfb_data, | ||
704 | .coherent_dma_mask = DMA_BIT_MASK(32), | ||
705 | .dma_mask = &ep93xx_fb_device.dev.coherent_dma_mask, | ||
706 | }, | ||
707 | .num_resources = ARRAY_SIZE(ep93xx_fb_resource), | ||
708 | .resource = ep93xx_fb_resource, | ||
709 | }; | ||
710 | |||
711 | void __init ep93xx_register_fb(struct ep93xxfb_mach_info *data) | ||
712 | { | ||
713 | ep93xxfb_data = *data; | ||
714 | platform_device_register(&ep93xx_fb_device); | ||
715 | } | ||
716 | |||
685 | extern void ep93xx_gpio_init(void); | 717 | extern void ep93xx_gpio_init(void); |
686 | 718 | ||
687 | void __init ep93xx_init_devices(void) | 719 | void __init ep93xx_init_devices(void) |
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h index ea78e908fc82..0fbf87b16338 100644 --- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h | |||
@@ -70,6 +70,7 @@ | |||
70 | #define EP93XX_USB_PHYS_BASE (EP93XX_AHB_PHYS_BASE + 0x00020000) | 70 | #define EP93XX_USB_PHYS_BASE (EP93XX_AHB_PHYS_BASE + 0x00020000) |
71 | #define EP93XX_USB_BASE EP93XX_AHB_IOMEM(0x00020000) | 71 | #define EP93XX_USB_BASE EP93XX_AHB_IOMEM(0x00020000) |
72 | 72 | ||
73 | #define EP93XX_RASTER_PHYS_BASE (EP93XX_AHB_PHYS_BASE + 0x00030000) | ||
73 | #define EP93XX_RASTER_BASE EP93XX_AHB_IOMEM(0x00030000) | 74 | #define EP93XX_RASTER_BASE EP93XX_AHB_IOMEM(0x00030000) |
74 | 75 | ||
75 | #define EP93XX_GRAPHICS_ACCEL_BASE EP93XX_AHB_IOMEM(0x00040000) | 76 | #define EP93XX_GRAPHICS_ACCEL_BASE EP93XX_AHB_IOMEM(0x00040000) |
@@ -207,6 +208,11 @@ | |||
207 | #define EP93XX_SYSCON_DEVCFG_ADCPD (1<<2) | 208 | #define EP93XX_SYSCON_DEVCFG_ADCPD (1<<2) |
208 | #define EP93XX_SYSCON_DEVCFG_KEYS (1<<1) | 209 | #define EP93XX_SYSCON_DEVCFG_KEYS (1<<1) |
209 | #define EP93XX_SYSCON_DEVCFG_SHENA (1<<0) | 210 | #define EP93XX_SYSCON_DEVCFG_SHENA (1<<0) |
211 | #define EP93XX_SYSCON_VIDCLKDIV EP93XX_SYSCON_REG(0x84) | ||
212 | #define EP93XX_SYSCON_CLKDIV_ENABLE (1<<15) | ||
213 | #define EP93XX_SYSCON_CLKDIV_ESEL (1<<14) | ||
214 | #define EP93XX_SYSCON_CLKDIV_PSEL (1<<13) | ||
215 | #define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT 8 | ||
210 | #define EP93XX_SYSCON_KEYTCHCLKDIV EP93XX_SYSCON_REG(0x90) | 216 | #define EP93XX_SYSCON_KEYTCHCLKDIV EP93XX_SYSCON_REG(0x90) |
211 | #define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN (1<<31) | 217 | #define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN (1<<31) |
212 | #define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV (1<<16) | 218 | #define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV (1<<16) |
diff --git a/arch/arm/mach-ep93xx/include/mach/fb.h b/arch/arm/mach-ep93xx/include/mach/fb.h new file mode 100644 index 000000000000..d5ae11d7c453 --- /dev/null +++ b/arch/arm/mach-ep93xx/include/mach/fb.h | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-ep93xx/include/mach/fb.h | ||
3 | */ | ||
4 | |||
5 | #ifndef __ASM_ARCH_EP93XXFB_H | ||
6 | #define __ASM_ARCH_EP93XXFB_H | ||
7 | |||
8 | struct platform_device; | ||
9 | struct fb_videomode; | ||
10 | struct fb_info; | ||
11 | |||
12 | #define EP93XXFB_USE_MODEDB 0 | ||
13 | |||
14 | /* VideoAttributes flags */ | ||
15 | #define EP93XXFB_STATE_MACHINE_ENABLE (1 << 0) | ||
16 | #define EP93XXFB_PIXEL_CLOCK_ENABLE (1 << 1) | ||
17 | #define EP93XXFB_VSYNC_ENABLE (1 << 2) | ||
18 | #define EP93XXFB_PIXEL_DATA_ENABLE (1 << 3) | ||
19 | #define EP93XXFB_COMPOSITE_SYNC (1 << 4) | ||
20 | #define EP93XXFB_SYNC_VERT_HIGH (1 << 5) | ||
21 | #define EP93XXFB_SYNC_HORIZ_HIGH (1 << 6) | ||
22 | #define EP93XXFB_SYNC_BLANK_HIGH (1 << 7) | ||
23 | #define EP93XXFB_PCLK_FALLING (1 << 8) | ||
24 | #define EP93XXFB_ENABLE_AC (1 << 9) | ||
25 | #define EP93XXFB_ENABLE_LCD (1 << 10) | ||
26 | #define EP93XXFB_ENABLE_CCIR (1 << 12) | ||
27 | #define EP93XXFB_USE_PARALLEL_INTERFACE (1 << 13) | ||
28 | #define EP93XXFB_ENABLE_INTERRUPT (1 << 14) | ||
29 | #define EP93XXFB_USB_INTERLACE (1 << 16) | ||
30 | #define EP93XXFB_USE_EQUALIZATION (1 << 17) | ||
31 | #define EP93XXFB_USE_DOUBLE_HORZ (1 << 18) | ||
32 | #define EP93XXFB_USE_DOUBLE_VERT (1 << 19) | ||
33 | #define EP93XXFB_USE_BLANK_PIXEL (1 << 20) | ||
34 | #define EP93XXFB_USE_SDCSN0 (0 << 21) | ||
35 | #define EP93XXFB_USE_SDCSN1 (1 << 21) | ||
36 | #define EP93XXFB_USE_SDCSN2 (2 << 21) | ||
37 | #define EP93XXFB_USE_SDCSN3 (3 << 21) | ||
38 | |||
39 | #define EP93XXFB_ENABLE (EP93XXFB_STATE_MACHINE_ENABLE | \ | ||
40 | EP93XXFB_PIXEL_CLOCK_ENABLE | \ | ||
41 | EP93XXFB_VSYNC_ENABLE | \ | ||
42 | EP93XXFB_PIXEL_DATA_ENABLE) | ||
43 | |||
44 | struct ep93xxfb_mach_info { | ||
45 | unsigned int num_modes; | ||
46 | const struct fb_videomode *modes; | ||
47 | const struct fb_videomode *default_mode; | ||
48 | int bpp; | ||
49 | unsigned int flags; | ||
50 | |||
51 | int (*setup)(struct platform_device *pdev); | ||
52 | void (*teardown)(struct platform_device *pdev); | ||
53 | void (*blank)(int blank_mode, struct fb_info *info); | ||
54 | }; | ||
55 | |||
56 | #endif /* __ASM_ARCH_EP93XXFB_H */ | ||
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h index 5f5fa6574d34..01a0f0838e5b 100644 --- a/arch/arm/mach-ep93xx/include/mach/platform.h +++ b/arch/arm/mach-ep93xx/include/mach/platform.h | |||
@@ -6,6 +6,7 @@ | |||
6 | 6 | ||
7 | struct i2c_board_info; | 7 | struct i2c_board_info; |
8 | struct platform_device; | 8 | struct platform_device; |
9 | struct ep93xxfb_mach_info; | ||
9 | 10 | ||
10 | struct ep93xx_eth_data | 11 | struct ep93xx_eth_data |
11 | { | 12 | { |
@@ -33,6 +34,7 @@ static inline void ep93xx_devcfg_clear_bits(unsigned int bits) | |||
33 | 34 | ||
34 | void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr); | 35 | void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr); |
35 | void ep93xx_register_i2c(struct i2c_board_info *devices, int num); | 36 | void ep93xx_register_i2c(struct i2c_board_info *devices, int num); |
37 | void ep93xx_register_fb(struct ep93xxfb_mach_info *data); | ||
36 | void ep93xx_register_pwm(int pwm0, int pwm1); | 38 | void ep93xx_register_pwm(int pwm0, int pwm1); |
37 | int ep93xx_pwm_acquire_gpio(struct platform_device *pdev); | 39 | int ep93xx_pwm_acquire_gpio(struct platform_device *pdev); |
38 | void ep93xx_pwm_release_gpio(struct platform_device *pdev); | 40 | void ep93xx_pwm_release_gpio(struct platform_device *pdev); |