Commit c6012189 authored by Ryan Mallon's avatar Ryan Mallon Committed by Linus Torvalds

ep93xx video driver platform support

Signed-off-by: default avatarRyan Mallon <ryan@bluewatersys.com>
Acked-by: default avatarH 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent d63870db
......@@ -37,7 +37,7 @@ struct clk {
static unsigned long get_uart_rate(struct clk *clk);
static int set_keytchclk_rate(struct clk *clk, unsigned long rate);
static int set_div_rate(struct clk *clk, unsigned long rate);
static struct clk clk_uart1 = {
.sw_locked = 1,
......@@ -76,6 +76,13 @@ static struct clk clk_pwm = {
.rate = EP93XX_EXT_CLK_RATE,
};
static struct clk clk_video = {
.sw_locked = 1,
.enable_reg = EP93XX_SYSCON_VIDCLKDIV,
.enable_mask = EP93XX_SYSCON_CLKDIV_ENABLE,
.set_rate = set_div_rate,
};
/* DMA Clocks */
static struct clk clk_m2p0 = {
.enable_reg = EP93XX_SYSCON_PWRCNT,
......@@ -140,6 +147,7 @@ static struct clk_lookup clocks[] = {
INIT_CK(NULL, "pll2", &clk_pll2),
INIT_CK("ep93xx-ohci", NULL, &clk_usb_host),
INIT_CK("ep93xx-keypad", NULL, &clk_keypad),
INIT_CK("ep93xx-fb", NULL, &clk_video),
INIT_CK(NULL, "pwm_clk", &clk_pwm),
INIT_CK(NULL, "m2p0", &clk_m2p0),
INIT_CK(NULL, "m2p1", &clk_m2p1),
......@@ -236,6 +244,84 @@ static int set_keytchclk_rate(struct clk *clk, unsigned long rate)
return 0;
}
static unsigned long calc_clk_div(unsigned long rate, int *psel, int *esel,
int *pdiv, int *div)
{
unsigned long max_rate, best_rate = 0,
actual_rate = 0, mclk_rate = 0, rate_err = -1;
int i, found = 0, __div = 0, __pdiv = 0;
/* Don't exceed the maximum rate */
max_rate = max(max(clk_pll1.rate / 4, clk_pll2.rate / 4),
(unsigned long)EP93XX_EXT_CLK_RATE / 4);
rate = min(rate, max_rate);
/*
* Try the two pll's and the external clock
* Because the valid predividers are 2, 2.5 and 3, we multiply
* all the clocks by 2 to avoid floating point math.
*
* This is based on the algorithm in the ep93xx raster guide:
* http://be-a-maverick.com/en/pubs/appNote/AN269REV1.pdf
*
*/
for (i = 0; i < 3; i++) {
if (i == 0)
mclk_rate = EP93XX_EXT_CLK_RATE * 2;
else if (i == 1)
mclk_rate = clk_pll1.rate * 2;
else if (i == 2)
mclk_rate = clk_pll2.rate * 2;
/* Try each predivider value */
for (__pdiv = 4; __pdiv <= 6; __pdiv++) {
__div = mclk_rate / (rate * __pdiv);
if (__div < 2 || __div > 127)
continue;
actual_rate = mclk_rate / (__pdiv * __div);
if (!found || abs(actual_rate - rate) < rate_err) {
*pdiv = __pdiv - 3;
*div = __div;
*psel = (i == 2);
*esel = (i != 0);
best_rate = actual_rate;
rate_err = abs(actual_rate - rate);
found = 1;
}
}
}
if (!found)
return 0;
return best_rate;
}
static int set_div_rate(struct clk *clk, unsigned long rate)
{
unsigned long actual_rate;
int psel = 0, esel = 0, pdiv = 0, div = 0;
u32 val;
actual_rate = calc_clk_div(rate, &psel, &esel, &pdiv, &div);
if (actual_rate == 0)
return -EINVAL;
clk->rate = actual_rate;
/* Clear the esel, psel, pdiv and div bits */
val = __raw_readl(clk->enable_reg);
val &= ~0x7fff;
/* Set the new esel, psel, pdiv and div bits for the new clock rate */
val |= (esel ? EP93XX_SYSCON_CLKDIV_ESEL : 0) |
(psel ? EP93XX_SYSCON_CLKDIV_PSEL : 0) |
(pdiv << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | div;
ep93xx_syscon_swlocked_write(val, clk->enable_reg);
return 0;
}
int clk_set_rate(struct clk *clk, unsigned long rate)
{
if (clk->set_rate)
......
......@@ -30,6 +30,7 @@
#include <linux/i2c-gpio.h>
#include <mach/hardware.h>
#include <mach/fb.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
......@@ -682,6 +683,37 @@ void ep93xx_pwm_release_gpio(struct platform_device *pdev)
EXPORT_SYMBOL(ep93xx_pwm_release_gpio);
/*************************************************************************
* EP93xx video peripheral handling
*************************************************************************/
static struct ep93xxfb_mach_info ep93xxfb_data;
static struct resource ep93xx_fb_resource[] = {
{
.start = EP93XX_RASTER_PHYS_BASE,
.end = EP93XX_RASTER_PHYS_BASE + 0x800 - 1,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device ep93xx_fb_device = {
.name = "ep93xx-fb",
.id = -1,
.dev = {
.platform_data = &ep93xxfb_data,
.coherent_dma_mask = DMA_BIT_MASK(32),
.dma_mask = &ep93xx_fb_device.dev.coherent_dma_mask,
},
.num_resources = ARRAY_SIZE(ep93xx_fb_resource),
.resource = ep93xx_fb_resource,
};
void __init ep93xx_register_fb(struct ep93xxfb_mach_info *data)
{
ep93xxfb_data = *data;
platform_device_register(&ep93xx_fb_device);
}
extern void ep93xx_gpio_init(void);
void __init ep93xx_init_devices(void)
......
......@@ -70,6 +70,7 @@
#define EP93XX_USB_PHYS_BASE (EP93XX_AHB_PHYS_BASE + 0x00020000)
#define EP93XX_USB_BASE EP93XX_AHB_IOMEM(0x00020000)
#define EP93XX_RASTER_PHYS_BASE (EP93XX_AHB_PHYS_BASE + 0x00030000)
#define EP93XX_RASTER_BASE EP93XX_AHB_IOMEM(0x00030000)
#define EP93XX_GRAPHICS_ACCEL_BASE EP93XX_AHB_IOMEM(0x00040000)
......@@ -207,6 +208,11 @@
#define EP93XX_SYSCON_DEVCFG_ADCPD (1<<2)
#define EP93XX_SYSCON_DEVCFG_KEYS (1<<1)
#define EP93XX_SYSCON_DEVCFG_SHENA (1<<0)
#define EP93XX_SYSCON_VIDCLKDIV EP93XX_SYSCON_REG(0x84)
#define EP93XX_SYSCON_CLKDIV_ENABLE (1<<15)
#define EP93XX_SYSCON_CLKDIV_ESEL (1<<14)
#define EP93XX_SYSCON_CLKDIV_PSEL (1<<13)
#define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT 8
#define EP93XX_SYSCON_KEYTCHCLKDIV EP93XX_SYSCON_REG(0x90)
#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN (1<<31)
#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV (1<<16)
......
/*
* arch/arm/mach-ep93xx/include/mach/fb.h
*/
#ifndef __ASM_ARCH_EP93XXFB_H
#define __ASM_ARCH_EP93XXFB_H
struct platform_device;
struct fb_videomode;
struct fb_info;
#define EP93XXFB_USE_MODEDB 0
/* VideoAttributes flags */
#define EP93XXFB_STATE_MACHINE_ENABLE (1 << 0)
#define EP93XXFB_PIXEL_CLOCK_ENABLE (1 << 1)
#define EP93XXFB_VSYNC_ENABLE (1 << 2)
#define EP93XXFB_PIXEL_DATA_ENABLE (1 << 3)
#define EP93XXFB_COMPOSITE_SYNC (1 << 4)
#define EP93XXFB_SYNC_VERT_HIGH (1 << 5)
#define EP93XXFB_SYNC_HORIZ_HIGH (1 << 6)
#define EP93XXFB_SYNC_BLANK_HIGH (1 << 7)
#define EP93XXFB_PCLK_FALLING (1 << 8)
#define EP93XXFB_ENABLE_AC (1 << 9)
#define EP93XXFB_ENABLE_LCD (1 << 10)
#define EP93XXFB_ENABLE_CCIR (1 << 12)
#define EP93XXFB_USE_PARALLEL_INTERFACE (1 << 13)
#define EP93XXFB_ENABLE_INTERRUPT (1 << 14)
#define EP93XXFB_USB_INTERLACE (1 << 16)
#define EP93XXFB_USE_EQUALIZATION (1 << 17)
#define EP93XXFB_USE_DOUBLE_HORZ (1 << 18)
#define EP93XXFB_USE_DOUBLE_VERT (1 << 19)
#define EP93XXFB_USE_BLANK_PIXEL (1 << 20)
#define EP93XXFB_USE_SDCSN0 (0 << 21)
#define EP93XXFB_USE_SDCSN1 (1 << 21)
#define EP93XXFB_USE_SDCSN2 (2 << 21)
#define EP93XXFB_USE_SDCSN3 (3 << 21)
#define EP93XXFB_ENABLE (EP93XXFB_STATE_MACHINE_ENABLE | \
EP93XXFB_PIXEL_CLOCK_ENABLE | \
EP93XXFB_VSYNC_ENABLE | \
EP93XXFB_PIXEL_DATA_ENABLE)
struct ep93xxfb_mach_info {
unsigned int num_modes;
const struct fb_videomode *modes;
const struct fb_videomode *default_mode;
int bpp;
unsigned int flags;
int (*setup)(struct platform_device *pdev);
void (*teardown)(struct platform_device *pdev);
void (*blank)(int blank_mode, struct fb_info *info);
};
#endif /* __ASM_ARCH_EP93XXFB_H */
......@@ -6,6 +6,7 @@
struct i2c_board_info;
struct platform_device;
struct ep93xxfb_mach_info;
struct ep93xx_eth_data
{
......@@ -33,6 +34,7 @@ static inline void ep93xx_devcfg_clear_bits(unsigned int bits)
void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr);
void ep93xx_register_i2c(struct i2c_board_info *devices, int num);
void ep93xx_register_fb(struct ep93xxfb_mach_info *data);
void ep93xx_register_pwm(int pwm0, int pwm1);
int ep93xx_pwm_acquire_gpio(struct platform_device *pdev);
void ep93xx_pwm_release_gpio(struct platform_device *pdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment