diff options
-rw-r--r-- | arch/arm/mach-shmobile/board-mackerel.c | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 42f7c0d67b53..c7d378b57cfc 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -21,6 +21,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <linux/delay.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/interrupt.h> @@ -43,6 +44,7 @@ #include <linux/tca6416_keypad.h> #include <linux/usb/r8a66597.h> +#include <video/sh_mobile_hdmi.h> #include <video/sh_mobile_lcdc.h> #include <media/sh_mobile_ceu.h> #include <media/soc_camera.h> @@ -332,6 +334,127 @@ static struct platform_device lcdc_device = { }, }; +/* HDMI */ +static struct sh_mobile_lcdc_info hdmi_lcdc_info = { + .clock_source = LCDC_CLK_EXTERNAL, + .ch[0] = { + .chan = LCDC_CHAN_MAINLCD, + .bpp = 16, + .interface_type = RGB24, + .clock_divider = 1, + .flags = LCDC_FLAGS_DWPOL, + } +}; + +static struct resource hdmi_lcdc_resources[] = { + [0] = { + .name = "LCDC1", + .start = 0xfe944000, + .end = 0xfe947fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = intcs_evt2irq(0x1780), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device hdmi_lcdc_device = { + .name = "sh_mobile_lcdc_fb", + .num_resources = ARRAY_SIZE(hdmi_lcdc_resources), + .resource = hdmi_lcdc_resources, + .id = 1, + .dev = { + .platform_data = &hdmi_lcdc_info, + .coherent_dma_mask = ~0, + }, +}; + +static struct sh_mobile_hdmi_info hdmi_info = { + .lcd_chan = &hdmi_lcdc_info.ch[0], + .lcd_dev = &hdmi_lcdc_device.dev, +}; + +static struct resource hdmi_resources[] = { + [0] = { + .name = "HDMI", + .start = 0xe6be0000, + .end = 0xe6be00ff, + .flags = IORESOURCE_MEM, + }, + [1] = { + /* There's also an HDMI interrupt on INTCS @ 0x18e0 */ + .start = evt2irq(0x17e0), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device hdmi_device = { + .name = "sh-mobile-hdmi", + .num_resources = ARRAY_SIZE(hdmi_resources), + .resource = hdmi_resources, + .id = -1, + .dev = { + .platform_data = &hdmi_info, + }, +}; + +static int __init hdmi_init_pm_clock(void) +{ + struct clk *hdmi_ick = clk_get(&hdmi_device.dev, "ick"); + int ret; + long rate; + + if (IS_ERR(hdmi_ick)) { + ret = PTR_ERR(hdmi_ick); + pr_err("Cannot get HDMI ICK: %d\n", ret); + goto out; + } + + ret = clk_set_parent(&sh7372_pllc2_clk, &sh7372_dv_clki_div2_clk); + if (ret < 0) { + pr_err("Cannot set PLLC2 parent: %d, %d users\n", + ret, sh7372_pllc2_clk.usecount); + goto out; + } + + pr_debug("PLLC2 initial frequency %lu\n", + clk_get_rate(&sh7372_pllc2_clk)); + + rate = clk_round_rate(&sh7372_pllc2_clk, 594000000); + if (rate < 0) { + pr_err("Cannot get suitable rate: %ld\n", rate); + ret = rate; + goto out; + } + + ret = clk_set_rate(&sh7372_pllc2_clk, rate); + if (ret < 0) { + pr_err("Cannot set rate %ld: %d\n", rate, ret); + goto out; + } + + ret = clk_enable(&sh7372_pllc2_clk); + if (ret < 0) { + pr_err("Cannot enable pllc2 clock\n"); + goto out; + } + + pr_debug("PLLC2 set frequency %lu\n", rate); + + ret = clk_set_parent(hdmi_ick, &sh7372_pllc2_clk); + if (ret < 0) { + pr_err("Cannot set HDMI parent: %d\n", ret); + goto out; + } + +out: + if (!IS_ERR(hdmi_ick)) + clk_put(hdmi_ick); + return ret; +} +device_initcall(hdmi_init_pm_clock); + /* USB1 (Host) */ static void usb1_host_port_power(int port, int power) { @@ -718,6 +841,8 @@ static struct platform_device *mackerel_devices[] __initdata = { &sh_mmcif_device, &ceu_device, &mackerel_camera, + &hdmi_lcdc_device, + &hdmi_device, }; /* Keypad Initialization */ @@ -793,8 +918,11 @@ static void __init mackerel_map_io(void) #define GPIO_PORT9CR 0xE6051009 #define GPIO_PORT10CR 0xE605100A +#define SRCR4 0xe61580bc static void __init mackerel_init(void) { + u32 srcr4; + sh7372_pinmux_init(); /* enable SCIFA0 */ @@ -935,6 +1063,16 @@ static void __init mackerel_init(void) gpio_request(GPIO_FN_VIO_D1, NULL); gpio_request(GPIO_FN_VIO_D0, NULL); + /* HDMI */ + gpio_request(GPIO_FN_HDMI_HPD, NULL); + gpio_request(GPIO_FN_HDMI_CEC, NULL); + + /* Reset HDMI, must be held at least one EXTALR (32768Hz) period */ + srcr4 = __raw_readl(SRCR4); + __raw_writel(srcr4 | (1 << 13), SRCR4); + udelay(50); + __raw_writel(srcr4 & ~(1 << 13), SRCR4); + i2c_register_board_info(0, i2c0_devices, ARRAY_SIZE(i2c0_devices)); i2c_register_board_info(1, i2c1_devices, @@ -949,6 +1087,9 @@ static void __init mackerel_timer_init(void) { sh7372_clock_init(); shmobile_timer.init(); + + /* External clock source */ + clk_set_rate(&sh7372_dv_clki_clk, 27000000); } static struct sys_timer mackerel_timer = { |