Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+87 −1
Original line number Diff line number Diff line
@@ -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)
+32 −0
Original line number Diff line number Diff line
@@ -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)
+6 −0
Original line number Diff line number Diff line
@@ -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)
+56 −0
Original line number Diff line number Diff line
/*
 * 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 */
+2 −0
Original line number Diff line number Diff line
@@ -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);