diff options
Diffstat (limited to 'arch/arm/mach-shmobile')
25 files changed, 2570 insertions, 32 deletions
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 34560cab45d9..98327b7a503c 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -41,6 +41,12 @@ config ARCH_R8A7779 select ARM_GIC select ARCH_WANT_OPTIONAL_GPIOLIB +config ARCH_EMEV2 + bool "Emma Mobile EV2" + select CPU_V7 + select ARM_GIC + select ARCH_WANT_OPTIONAL_GPIOLIB + comment "SH-Mobile Board Type" config MACH_G3EVM @@ -93,11 +99,28 @@ config MACH_BONITO select ARCH_REQUIRE_GPIOLIB depends on ARCH_R8A7740 +config MACH_ARMADILLO800EVA + bool "Armadillo-800 EVA board" + depends on ARCH_R8A7740 + select ARCH_REQUIRE_GPIOLIB + select USE_OF + config MACH_MARZEN bool "MARZEN board" depends on ARCH_R8A7779 select ARCH_REQUIRE_GPIOLIB +config MACH_KZM9D + bool "KZM9D board" + depends on ARCH_EMEV2 + select USE_OF + +config MACH_KZM9G + bool "KZM-A9-GT board" + depends on ARCH_SH73A0 + select ARCH_REQUIRE_GPIOLIB + select USE_OF + comment "SH-Mobile System Configuration" config CPU_HAS_INTEVT @@ -110,7 +133,8 @@ config MEMORY_START hex "Physical memory start address" default "0x50000000" if MACH_G3EVM default "0x40000000" if MACH_G4EVM || MACH_AP4EVB || MACH_AG5EVM || \ - MACH_MACKEREL || MACH_BONITO + MACH_MACKEREL || MACH_BONITO || \ + MACH_ARMADILLO800EVA default "0x41000000" if MACH_KOTA2 default "0x00000000" ---help--- @@ -122,7 +146,8 @@ config MEMORY_SIZE hex "Physical memory size" default "0x08000000" if MACH_G3EVM default "0x08000000" if MACH_G4EVM - default "0x20000000" if MACH_AG5EVM || MACH_BONITO + default "0x20000000" if MACH_AG5EVM || MACH_BONITO || \ + MACH_ARMADILLO800EVA default "0x1e000000" if MACH_KOTA2 default "0x10000000" if MACH_AP4EVB || MACH_MACKEREL default "0x04000000" diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index e7c2590b75d9..e6b177bc9410 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -12,12 +12,14 @@ obj-$(CONFIG_ARCH_SH7372) += setup-sh7372.o clock-sh7372.o intc-sh7372.o obj-$(CONFIG_ARCH_SH73A0) += setup-sh73a0.o clock-sh73a0.o intc-sh73a0.o obj-$(CONFIG_ARCH_R8A7740) += setup-r8a7740.o clock-r8a7740.o intc-r8a7740.o obj-$(CONFIG_ARCH_R8A7779) += setup-r8a7779.o clock-r8a7779.o intc-r8a7779.o +obj-$(CONFIG_ARCH_EMEV2) += setup-emev2.o clock-emev2.o # SMP objects smp-y := platsmp.o headsmp.o smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o smp-$(CONFIG_ARCH_R8A7779) += smp-r8a7779.o +smp-$(CONFIG_ARCH_EMEV2) += smp-emev2.o # Pinmux setup pfc-y := @@ -49,6 +51,9 @@ obj-$(CONFIG_MACH_MACKEREL) += board-mackerel.o obj-$(CONFIG_MACH_KOTA2) += board-kota2.o obj-$(CONFIG_MACH_BONITO) += board-bonito.o obj-$(CONFIG_MACH_MARZEN) += board-marzen.o +obj-$(CONFIG_MACH_ARMADILLO800EVA) += board-armadillo800eva.o +obj-$(CONFIG_MACH_KZM9D) += board-kzm9d.o +obj-$(CONFIG_MACH_KZM9G) += board-kzm9g.o # Framework support obj-$(CONFIG_SMP) += $(smp-y) diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index b56dde2732bb..0c3caeba2f3e 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -997,6 +997,8 @@ static struct sh_mobile_ceu_companion csi2 = { static struct sh_mobile_ceu_info sh_mobile_ceu_info = { .flags = SH_CEU_FLAG_USE_8BIT_BUS, + .max_width = 8188, + .max_height = 8188, .csi2 = &csi2, }; diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c new file mode 100644 index 000000000000..9e37026ef9dd --- /dev/null +++ b/arch/arm/mach-shmobile/board-armadillo800eva.c @@ -0,0 +1,784 @@ +/* + * armadillo 800 eva board support + * + * Copyright (C) 2012 Renesas Solutions Corp. + * Copyright (C) 2012 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * 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/clk.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/input.h> +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/gpio_keys.h> +#include <linux/sh_eth.h> +#include <linux/videodev2.h> +#include <linux/usb/renesas_usbhs.h> +#include <linux/mfd/tmio.h> +#include <linux/mmc/host.h> +#include <linux/mmc/sh_mmcif.h> +#include <linux/mmc/sh_mobile_sdhi.h> +#include <mach/common.h> +#include <mach/irqs.h> +#include <asm/page.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/time.h> +#include <asm/hardware/cache-l2x0.h> +#include <mach/r8a7740.h> +#include <video/sh_mobile_lcdc.h> + +/* + * CON1 Camera Module + * CON2 Extension Bus + * CON3 HDMI Output + * CON4 Composite Video Output + * CON5 H-UDI JTAG + * CON6 ARM JTAG + * CON7 SD1 + * CON8 SD2 + * CON9 RTC BackUp + * CON10 Monaural Mic Input + * CON11 Stereo Headphone Output + * CON12 Audio Line Output(L) + * CON13 Audio Line Output(R) + * CON14 AWL13 Module + * CON15 Extension + * CON16 LCD1 + * CON17 LCD2 + * CON19 Power Input + * CON20 USB1 + * CON21 USB2 + * CON22 Serial + * CON23 LAN + * CON24 USB3 + * LED1 Camera LED(Yellow) + * LED2 Power LED (Green) + * ED3-LED6 User LED(Yellow) + * LED7 LAN link LED(Green) + * LED8 LAN activity LED(Yellow) + */ + +/* + * DipSwitch + * + * SW1 + * + * -12345678-+---------------+---------------------------- + * 1 | boot | hermit + * 0 | boot | OS auto boot + * -12345678-+---------------+---------------------------- + * 00 | boot device | eMMC + * 10 | boot device | SDHI0 (CON7) + * 01 | boot device | - + * 11 | boot device | Extension Buss (CS0) + * -12345678-+---------------+---------------------------- + * 0 | Extension Bus | D8-D15 disable, eMMC enable + * 1 | Extension Bus | D8-D15 enable, eMMC disable + * -12345678-+---------------+---------------------------- + * 0 | SDHI1 | COM8 disable, COM14 enable + * 1 | SDHI1 | COM8 enable, COM14 disable + * -12345678-+---------------+---------------------------- + * 0 | USB0 | COM20 enable, COM24 disable + * 1 | USB0 | COM20 disable, COM24 enable + * -12345678-+---------------+---------------------------- + * 00 | JTAG | SH-X2 + * 10 | JTAG | ARM + * 01 | JTAG | - + * 11 | JTAG | Boundary Scan + *-----------+---------------+---------------------------- + */ + +/* + * USB function + * + * When you use USB Function, + * set SW1.6 ON, and connect cable to CN24. + * + * USBF needs workaround on R8A7740 chip. + * These are a little bit complex. + * see + * usbhsf_power_ctrl() + * + * CAUTION + * + * It uses autonomy mode for USB hotplug at this point + * (= usbhs_private.platform_callback.get_vbus is NULL), + * since we don't know what's happen on PM control + * on this workaround. + */ +#define USBCR1 0xe605810a +#define USBH 0xC6700000 +#define USBH_USBCTR 0x10834 + +struct usbhsf_private { + struct clk *phy; + struct clk *usb24; + struct clk *pci; + struct clk *func; + struct clk *host; + void __iomem *usbh_base; + struct renesas_usbhs_platform_info info; +}; + +#define usbhsf_get_priv(pdev) \ + container_of(renesas_usbhs_get_info(pdev), \ + struct usbhsf_private, info) + +static int usbhsf_get_id(struct platform_device *pdev) +{ + return USBHS_GADGET; +} + +static void usbhsf_power_ctrl(struct platform_device *pdev, + void __iomem *base, int enable) +{ + struct usbhsf_private *priv = usbhsf_get_priv(pdev); + + /* + * Work around for USB Function. + * It needs USB host clock, and settings + */ + if (enable) { + /* + * enable all the related usb clocks + * for usb workaround + */ + clk_enable(priv->usb24); + clk_enable(priv->pci); + clk_enable(priv->host); + clk_enable(priv->func); + clk_enable(priv->phy); + + /* + * set USBCR1 + * + * Port1 is driven by USB function, + * Port2 is driven by USB HOST + * One HOST (Port1 or Port2 is HOST) + * USB PLL input clock = 24MHz + */ + __raw_writew(0xd750, USBCR1); + mdelay(1); + + /* + * start USB Host + */ + __raw_writel(0x0000000c, priv->usbh_base + USBH_USBCTR); + __raw_writel(0x00000008, priv->usbh_base + USBH_USBCTR); + mdelay(10); + + /* + * USB PHY Power ON + */ + __raw_writew(0xd770, USBCR1); + __raw_writew(0x4000, base + 0x102); /* USBF :: SUSPMODE */ + + } else { + __raw_writel(0x0000010f, priv->usbh_base + USBH_USBCTR); + __raw_writew(0xd7c0, USBCR1); /* GPIO */ + + clk_disable(priv->phy); + clk_disable(priv->func); /* usb work around */ + clk_disable(priv->host); /* usb work around */ + clk_disable(priv->pci); /* usb work around */ + clk_disable(priv->usb24); /* usb work around */ + } +} + +static void usbhsf_hardware_exit(struct platform_device *pdev) +{ + struct usbhsf_private *priv = usbhsf_get_priv(pdev); + + if (!IS_ERR(priv->phy)) + clk_put(priv->phy); + if (!IS_ERR(priv->usb24)) + clk_put(priv->usb24); + if (!IS_ERR(priv->pci)) + clk_put(priv->pci); + if (!IS_ERR(priv->host)) + clk_put(priv->host); + if (!IS_ERR(priv->func)) + clk_put(priv->func); + if (priv->usbh_base) + iounmap(priv->usbh_base); + + priv->phy = NULL; + priv->usb24 = NULL; + priv->pci = NULL; + priv->host = NULL; + priv->func = NULL; + priv->usbh_base = NULL; +} + +static int usbhsf_hardware_init(struct platform_device *pdev) +{ + struct usbhsf_private *priv = usbhsf_get_priv(pdev); + + priv->phy = clk_get(&pdev->dev, "phy"); + priv->usb24 = clk_get(&pdev->dev, "usb24"); + priv->pci = clk_get(&pdev->dev, "pci"); + priv->func = clk_get(&pdev->dev, "func"); + priv->host = clk_get(&pdev->dev, "host"); + priv->usbh_base = ioremap_nocache(USBH, 0x20000); + + if (IS_ERR(priv->phy) || + IS_ERR(priv->usb24) || + IS_ERR(priv->pci) || + IS_ERR(priv->host) || + IS_ERR(priv->func) || + !priv->usbh_base) { + dev_err(&pdev->dev, "USB clock setting failed\n"); + usbhsf_hardware_exit(pdev); + return -EIO; + } + + /* usb24 use 1/1 of parent clock (= usb24s = 24MHz) */ + clk_set_rate(priv->usb24, + clk_get_rate(clk_get_parent(priv->usb24))); + + return 0; +} + +static struct usbhsf_private usbhsf_private = { + .info = { + .platform_callback = { + .get_id = usbhsf_get_id, + .hardware_init = usbhsf_hardware_init, + .hardware_exit = usbhsf_hardware_exit, + .power_ctrl = usbhsf_power_ctrl, + }, + .driver_param = { + .buswait_bwait = 5, + .detection_delay = 5, + }, + } +}; + +static struct resource usbhsf_resources[] = { + { + .name = "USBHS", + .start = 0xe6890000, + .end = 0xe6890104 - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = evt2irq(0x0A20), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device usbhsf_device = { + .name = "renesas_usbhs", + .dev = { + .platform_data = &usbhsf_private.info, + }, + .id = -1, + .num_resources = ARRAY_SIZE(usbhsf_resources), + .resource = usbhsf_resources, +}; + +/* Ether */ +static struct sh_eth_plat_data sh_eth_platdata = { + .phy = 0x00, /* LAN8710A */ + .edmac_endian = EDMAC_LITTLE_ENDIAN, + .register_type = SH_ETH_REG_GIGABIT, + .phy_interface = PHY_INTERFACE_MODE_MII, +}; + +static struct resource sh_eth_resources[] = { + { + .start = 0xe9a00000, + .end = 0xe9a00800 - 1, + .flags = IORESOURCE_MEM, + }, { + .start = 0xe9a01800, + .end = 0xe9a02000 - 1, + .flags = IORESOURCE_MEM, + }, { + .start = evt2irq(0x0500), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device sh_eth_device = { + .name = "sh-eth", + .id = -1, + .dev = { + .platform_data = &sh_eth_platdata, + }, + .resource = sh_eth_resources, + .num_resources = ARRAY_SIZE(sh_eth_resources), +}; + +/* LCDC */ +static struct fb_videomode lcdc0_mode = { + .name = "AMPIER/AM-800480", + .xres = 800, + .yres = 480, + .left_margin = 88, + .right_margin = 40, + .hsync_len = 128, + .upper_margin = 20, + .lower_margin = 5, + .vsync_len = 5, + .sync = 0, +}; + +static struct sh_mobile_lcdc_info lcdc0_info = { + .clock_source = LCDC_CLK_BUS, + .ch[0] = { + .chan = LCDC_CHAN_MAINLCD, + .fourcc = V4L2_PIX_FMT_RGB565, + .interface_type = RGB24, + .clock_divider = 5, + .flags = 0, + .lcd_modes = &lcdc0_mode, + .num_modes = 1, + .panel_cfg = { + .width = 111, + .height = 68, + }, + }, +}; + +static struct resource lcdc0_resources[] = { + [0] = { + .name = "LCD0", + .start = 0xfe940000, + .end = 0xfe943fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = intcs_evt2irq(0x580), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device lcdc0_device = { + .name = "sh_mobile_lcdc_fb", + .num_resources = ARRAY_SIZE(lcdc0_resources), + .resource = lcdc0_resources, + .id = 0, + .dev = { + .platform_data = &lcdc0_info, + .coherent_dma_mask = ~0, + }, +}; + +/* GPIO KEY */ +#define GPIO_KEY(c, g, d) { .code = c, .gpio = g, .desc = d, .active_low = 1 } + +static struct gpio_keys_button gpio_buttons[] = { + GPIO_KEY(KEY_POWER, GPIO_PORT99, "SW1"), + GPIO_KEY(KEY_BACK, GPIO_PORT100, "SW2"), + GPIO_KEY(KEY_MENU, GPIO_PORT97, "SW3"), + GPIO_KEY(KEY_HOME, GPIO_PORT98, "SW4"), +}; + +static struct gpio_keys_platform_data gpio_key_info = { + .buttons = gpio_buttons, + .nbuttons = ARRAY_SIZE(gpio_buttons), +}; + +static struct platform_device gpio_keys_device = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &gpio_key_info, + }, +}; + +/* SDHI0 */ +/* + * FIXME + * + * It use polling mode here, since + * CD (= Card Detect) pin is not connected to SDHI0_CD. + * We can use IRQ31 as card detect irq, + * but it needs chattering removal operation + */ +#define IRQ31 evt2irq(0x33E0) +static struct sh_mobile_sdhi_info sdhi0_info = { + .tmio_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |\ + MMC_CAP_NEEDS_POLL, + .tmio_ocr_mask = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34, + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT, +}; + +static struct resource sdhi0_resources[] = { + { + .name = "SDHI0", + .start = 0xe6850000, + .end = 0xe6850100 - 1, + .flags = IORESOURCE_MEM, + }, + /* + * no SH_MOBILE_SDHI_IRQ_CARD_DETECT here + */ + { + .name = SH_MOBILE_SDHI_IRQ_SDCARD, + .start = evt2irq(0x0E20), + .flags = IORESOURCE_IRQ, + }, + { + .name = SH_MOBILE_SDHI_IRQ_SDIO, + .start = evt2irq(0x0E40), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device sdhi0_device = { + .name = "sh_mobile_sdhi", + .id = 0, + .dev = { + .platform_data = &sdhi0_info, + }, + .num_resources = ARRAY_SIZE(sdhi0_resources), + .resource = sdhi0_resources, +}; + +/* SDHI1 */ +static struct sh_mobile_sdhi_info sdhi1_info = { + .tmio_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, + .tmio_ocr_mask = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34, + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT, +}; + +static struct resource sdhi1_resources[] = { + [0] = { + .name = "SDHI1", + .start = 0xe6860000, + .end = 0xe6860100 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = evt2irq(0x0E80), + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = evt2irq(0x0EA0), + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = evt2irq(0x0EC0), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device sdhi1_device = { + .name = "sh_mobile_sdhi", + .id = 1, + .dev = { + .platform_data = &sdhi1_info, + }, + .num_resources = ARRAY_SIZE(sdhi1_resources), + .resource = sdhi1_resources, +}; + +/* MMCIF */ +static struct sh_mmcif_plat_data sh_mmcif_plat = { + .sup_pclk = 0, + .ocr = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34, + .caps = MMC_CAP_4_BIT_DATA | + MMC_CAP_8_BIT_DATA | + MMC_CAP_NONREMOVABLE, +}; + +static struct resource sh_mmcif_resources[] = { + [0] = { + .name = "MMCIF", + .start = 0xe6bd0000, + .end = 0xe6bd0100 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + /* MMC ERR */ + .start = evt2irq(0x1AC0), + .flags = IORESOURCE_IRQ, + }, + [2] = { + /* MMC NOR */ + .start = evt2irq(0x1AE0), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device sh_mmcif_device = { + .name = "sh_mmcif", + .id = -1, + .dev = { + .platform_data = &sh_mmcif_plat, + }, + .num_resources = ARRAY_SIZE(sh_mmcif_resources), + .resource = sh_mmcif_resources, +}; + +/* I2C */ +static struct i2c_board_info i2c0_devices[] = { + { + I2C_BOARD_INFO("st1232-ts", 0x55), + .irq = evt2irq(0x0340), + }, +}; + +/* + * board devices + */ +static struct platform_device *eva_devices[] __initdata = { + &lcdc0_device, + &gpio_keys_device, + &sh_eth_device, + &sdhi0_device, + &sh_mmcif_device, +}; + +static void __init eva_clock_init(void) +{ + struct clk *system = clk_get(NULL, "system_clk"); + struct clk *xtal1 = clk_get(NULL, "extal1"); + struct clk *usb24s = clk_get(NULL, "usb24s"); + + if (IS_ERR(system) || + IS_ERR(xtal1) || + IS_ERR(usb24s)) { + pr_err("armadillo800eva board clock init failed\n"); + goto clock_error; + } + + /* armadillo 800 eva extal1 is 24MHz */ + clk_set_rate(xtal1, 24000000); + + /* usb24s use extal1 (= system) clock (= 24MHz) */ + clk_set_parent(usb24s, system); + +clock_error: + if (!IS_ERR(system)) + clk_put(system); + if (!IS_ERR(xtal1)) + clk_put(xtal1); + if (!IS_ERR(usb24s)) + clk_put(usb24s); +} + +/* + * board init + */ +static void __init eva_init(void) +{ + eva_clock_init(); + + r8a7740_pinmux_init(); + + /* SCIFA1 */ + gpio_request(GPIO_FN_SCIFA1_RXD, NULL); + gpio_request(GPIO_FN_SCIFA1_TXD, NULL); + + /* LCDC0 */ + gpio_request(GPIO_FN_LCDC0_SELECT, NULL); + gpio_request(GPIO_FN_LCD0_D0, NULL); + gpio_request(GPIO_FN_LCD0_D1, NULL); + gpio_request(GPIO_FN_LCD0_D2, NULL); + gpio_request(GPIO_FN_LCD0_D3, NULL); + gpio_request(GPIO_FN_LCD0_D4, NULL); + gpio_request(GPIO_FN_LCD0_D5, NULL); + gpio_request(GPIO_FN_LCD0_D6, NULL); + gpio_request(GPIO_FN_LCD0_D7, NULL); + gpio_request(GPIO_FN_LCD0_D8, NULL); + gpio_request(GPIO_FN_LCD0_D9, NULL); + gpio_request(GPIO_FN_LCD0_D10, NULL); + gpio_request(GPIO_FN_LCD0_D11, NULL); + gpio_request(GPIO_FN_LCD0_D12, NULL); + gpio_request(GPIO_FN_LCD0_D13, NULL); + gpio_request(GPIO_FN_LCD0_D14, NULL); + gpio_request(GPIO_FN_LCD0_D15, NULL); + gpio_request(GPIO_FN_LCD0_D16, NULL); + gpio_request(GPIO_FN_LCD0_D17, NULL); + gpio_request(GPIO_FN_LCD0_D18_PORT40, NULL); + gpio_request(GPIO_FN_LCD0_D19_PORT4, NULL); + gpio_request(GPIO_FN_LCD0_D20_PORT3, NULL); + gpio_request(GPIO_FN_LCD0_D21_PORT2, NULL); + gpio_request(GPIO_FN_LCD0_D22_PORT0, NULL); + gpio_request(GPIO_FN_LCD0_D23_PORT1, NULL); + gpio_request(GPIO_FN_LCD0_DCK, NULL); + gpio_request(GPIO_FN_LCD0_VSYN, NULL); + gpio_request(GPIO_FN_LCD0_HSYN, NULL); + gpio_request(GPIO_FN_LCD0_DISP, NULL); + gpio_request(GPIO_FN_LCD0_LCLK_PORT165, NULL); + + gpio_request(GPIO_PORT61, NULL); /* LCDDON */ + gpio_direction_output(GPIO_PORT61, 1); + + gpio_request(GPIO_PORT202, NULL); /* LCD0_LED_CONT */ + gpio_direction_output(GPIO_PORT202, 0); + + /* Touchscreen */ + gpio_request(GPIO_FN_IRQ10, NULL); /* TP_INT */ + gpio_request(GPIO_PORT166, NULL); /* TP_RST_B */ + gpio_direction_output(GPIO_PORT166, 1); + + /* GETHER */ + gpio_request(GPIO_FN_ET_CRS, NULL); + gpio_request(GPIO_FN_ET_MDC, NULL); + gpio_request(GPIO_FN_ET_MDIO, NULL); + gpio_request(GPIO_FN_ET_TX_ER, NULL); + gpio_request(GPIO_FN_ET_RX_ER, NULL); + gpio_request(GPIO_FN_ET_ERXD0, NULL); + gpio_request(GPIO_FN_ET_ERXD1, NULL); + gpio_request(GPIO_FN_ET_ERXD2, NULL); + gpio_request(GPIO_FN_ET_ERXD3, NULL); + gpio_request(GPIO_FN_ET_TX_CLK, NULL); + gpio_request(GPIO_FN_ET_TX_EN, NULL); + gpio_request(GPIO_FN_ET_ETXD0, NULL); + gpio_request(GPIO_FN_ET_ETXD1, NULL); + gpio_request(GPIO_FN_ET_ETXD2, NULL); + gpio_request(GPIO_FN_ET_ETXD3, NULL); + gpio_request(GPIO_FN_ET_PHY_INT, NULL); + gpio_request(GPIO_FN_ET_COL, NULL); + gpio_request(GPIO_FN_ET_RX_DV, NULL); + gpio_request(GPIO_FN_ET_RX_CLK, NULL); + + gpio_request(GPIO_PORT18, NULL); /* PHY_RST */ + gpio_direction_output(GPIO_PORT18, 1); + + /* USB */ + gpio_request(GPIO_PORT159, NULL); /* USB_DEVICE_MODE */ + gpio_direction_input(GPIO_PORT159); + + if (gpio_get_value(GPIO_PORT159)) { + /* USB Host */ + } else { + /* USB Func */ + gpio_request(GPIO_FN_VBUS, NULL); + platform_device_register(&usbhsf_device); + } + + /* SDHI0 */ + gpio_request(GPIO_FN_SDHI0_CMD, NULL); + gpio_request(GPIO_FN_SDHI0_CLK, NULL); + gpio_request(GPIO_FN_SDHI0_D0, NULL); + gpio_request(GPIO_FN_SDHI0_D1, NULL); + gpio_request(GPIO_FN_SDHI0_D2, NULL); + gpio_request(GPIO_FN_SDHI0_D3, NULL); + gpio_request(GPIO_FN_SDHI0_WP, NULL); + + gpio_request(GPIO_PORT17, NULL); /* SDHI0_18/33_B */ + gpio_request(GPIO_PORT74, NULL); /* SDHI0_PON */ + gpio_request(GPIO_PORT75, NULL); /* SDSLOT1_PON */ + gpio_direction_output(GPIO_PORT17, 0); + gpio_direction_output(GPIO_PORT74, 1); + gpio_direction_output(GPIO_PORT75, 1); + + /* we can use GPIO_FN_IRQ31_PORT167 here for SDHI0 CD irq */ + + /* + * MMCIF + * + * Here doesn't care SW1.4 status, + * since CON2 is not mounted. + */ + gpio_request(GPIO_FN_MMC1_CLK_PORT103, NULL); + gpio_request(GPIO_FN_MMC1_CMD_PORT104, NULL); + gpio_request(GPIO_FN_MMC1_D0_PORT149, NULL); + gpio_request(GPIO_FN_MMC1_D1_PORT148, NULL); + gpio_request(GPIO_FN_MMC1_D2_PORT147, NULL); + gpio_request(GPIO_FN_MMC1_D3_PORT146, NULL); + gpio_request(GPIO_FN_MMC1_D4_PORT145, NULL); + gpio_request(GPIO_FN_MMC1_D5_PORT144, NULL); + gpio_request(GPIO_FN_MMC1_D6_PORT143, NULL); + gpio_request(GPIO_FN_MMC1_D7_PORT142, NULL); + + /* + * CAUTION + * + * DBGMD/LCDC0/FSIA MUX + * DBGMD_SELECT_B should be set after setting PFC Function. + */ + gpio_request(GPIO_PORT176, NULL); + gpio_direction_output(GPIO_PORT176, 1); + + /* + * We can switch CON8/CON14 by SW1.5, + * but it needs after DBGMD_SELECT_B + */ + gpio_request(GPIO_PORT6, NULL); + gpio_direction_input(GPIO_PORT6); + if (gpio_get_value(GPIO_PORT6)) { + /* CON14 enable */ + } else { + /* CON8 (SDHI1) enable */ + gpio_request(GPIO_FN_SDHI1_CLK, NULL); + gpio_request(GPIO_FN_SDHI1_CMD, NULL); + gpio_request(GPIO_FN_SDHI1_D0, NULL); + gpio_request(GPIO_FN_SDHI1_D1, NULL); + gpio_request(GPIO_FN_SDHI1_D2, NULL); + gpio_request(GPIO_FN_SDHI1_D3, NULL); + gpio_request(GPIO_FN_SDHI1_CD, NULL); + gpio_request(GPIO_FN_SDHI1_WP, NULL); + + gpio_request(GPIO_PORT16, NULL); /* SDSLOT2_PON */ + gpio_direction_output(GPIO_PORT16, 1); + + platform_device_register(&sdhi1_device); + } + + +#ifdef CONFIG_CACHE_L2X0 + /* Early BRESP enable, Shared attribute override enable, 32K*8way */ + l2x0_init(__io(0xf0002000), 0x40440000, 0x82000fff); +#endif + + i2c_register_board_info(0, i2c0_devices, ARRAY_SIZE(i2c0_devices)); + + r8a7740_add_standard_devices(); + + platform_add_devices(eva_devices, + ARRAY_SIZE(eva_devices)); +} + +static void __init eva_earlytimer_init(void) +{ + r8a7740_clock_init(MD_CK0 | MD_CK2); + shmobile_earlytimer_init(); +} + +static void __init eva_add_early_devices(void) +{ + r8a7740_add_early_devices(); + + /* override timer setup with board-specific code */ + shmobile_timer.init = eva_earlytimer_init; +} + +static const char *eva_boards_compat_dt[] __initdata = { + "renesas,armadillo800eva", + NULL, +}; + +DT_MACHINE_START(ARMADILLO800EVA_DT, "armadillo800eva") + .map_io = r8a7740_map_io, + .init_early = eva_add_early_devices, + .init_irq = r8a7740_init_irq, + .handle_irq = shmobile_handle_irq_intc, + .init_machine = eva_init, + .timer = &shmobile_timer, + .dt_compat = eva_boards_compat_dt, +MACHINE_END diff --git a/arch/arm/mach-shmobile/board-bonito.c b/arch/arm/mach-shmobile/board-bonito.c index 81fd95f7f52a..63ab7062bee3 100644 --- a/arch/arm/mach-shmobile/board-bonito.c +++ b/arch/arm/mach-shmobile/board-bonito.c @@ -486,7 +486,7 @@ static void __init bonito_earlytimer_init(void) shmobile_earlytimer_init(); } -void __init bonito_add_early_devices(void) +static void __init bonito_add_early_devices(void) { r8a7740_add_early_devices(); diff --git a/arch/arm/mach-shmobile/board-kzm9d.c b/arch/arm/mach-shmobile/board-kzm9d.c new file mode 100644 index 000000000000..7bc5e7d39f9b --- /dev/null +++ b/arch/arm/mach-shmobile/board-kzm9d.c @@ -0,0 +1,85 @@ +/* + * kzm9d board support + * + * Copyright (C) 2012 Renesas Solutions Corp. + * Copyright (C) 2012 Magnus Damm + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * 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/kernel.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/smsc911x.h> +#include <mach/common.h> +#include <mach/emev2.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/hardware/gic.h> + +/* Ether */ +static struct resource smsc911x_resources[] = { + [0] = { + .start = 0x20000000, + .end = 0x2000ffff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = EMEV2_GPIO_IRQ(1), + .flags = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH, + }, +}; + +static struct smsc911x_platform_config smsc911x_platdata = { + .flags = SMSC911X_USE_32BIT, + .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH, +}; + +static struct platform_device smsc91x_device = { + .name = "smsc911x", + .id = 0, + .dev = { + .platform_data = &smsc911x_platdata, + }, + .num_resources = ARRAY_SIZE(smsc911x_resources), + .resource = smsc911x_resources, +}; + +static struct platform_device *kzm9d_devices[] __initdata = { + &smsc91x_device, +}; + +void __init kzm9d_add_standard_devices(void) +{ + emev2_add_standard_devices(); + + platform_add_devices(kzm9d_devices, ARRAY_SIZE(kzm9d_devices)); +} + +static const char *kzm9d_boards_compat_dt[] __initdata = { + "renesas,kzm9d", + NULL, +}; + +DT_MACHINE_START(KZM9D_DT, "kzm9d") + .map_io = emev2_map_io, + .init_early = emev2_add_early_devices, + .nr_irqs = NR_IRQS_LEGACY, + .init_irq = emev2_init_irq, + .handle_irq = gic_handle_irq, + .init_machine = kzm9d_add_standard_devices, + .timer = &shmobile_timer, + .dt_compat = kzm9d_boards_compat_dt, +MACHINE_END diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c new file mode 100644 index 000000000000..d8e33b682832 --- /dev/null +++ b/arch/arm/mach-shmobile/board-kzm9g.c @@ -0,0 +1,460 @@ +/* + * KZM-A9-GT board support + * + * Copyright (C) 2012 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * 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/gpio.h> +#include <linux/gpio_keys.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/i2c.h> +#include <linux/i2c/pcf857x.h> +#include <linux/input.h> +#include <linux/mmc/host.h> +#include <linux/mmc/sh_mmcif.h> +#include <linux/mmc/sh_mobile_sdhi.h> +#include <linux/mfd/tmio.h> +#include <linux/platform_device.h> +#include <linux/smsc911x.h> +#include <linux/usb/r8a66597.h> +#include <linux/videodev2.h> +#include <mach/irqs.h> +#include <mach/sh73a0.h> +#include <mach/common.h> +#include <asm/hardware/cache-l2x0.h> +#include <asm/hardware/gic.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <video/sh_mobile_lcdc.h> + +/* + * external GPIO + */ +#define GPIO_PCF8575_BASE (GPIO_NR) +#define GPIO_PCF8575_PORT10 (GPIO_NR + 8) +#define GPIO_PCF8575_PORT11 (GPIO_NR + 9) +#define GPIO_PCF8575_PORT12 (GPIO_NR + 10) +#define GPIO_PCF8575_PORT13 (GPIO_NR + 11) +#define GPIO_PCF8575_PORT14 (GPIO_NR + 12) +#define GPIO_PCF8575_PORT15 (GPIO_NR + 13) +#define GPIO_PCF8575_PORT16 (GPIO_NR + 14) + +/* SMSC 9221 */ +static struct resource smsc9221_resources[] = { + [0] = { + .start = 0x10000000, /* CS4 */ + .end = 0x100000ff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = intcs_evt2irq(0x260), /* IRQ3 */ + .flags = IORESOURCE_IRQ, + }, +}; + +static struct smsc911x_platform_config smsc9221_platdata = { + .flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS, + .phy_interface = PHY_INTERFACE_MODE_MII, + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, +}; + +static struct platform_device smsc_device = { + .name = "smsc911x", + .dev = { + .platform_data = &smsc9221_platdata, + }, + .resource = smsc9221_resources, + .num_resources = ARRAY_SIZE(smsc9221_resources), +}; + +/* USB external chip */ +static struct r8a66597_platdata usb_host_data = { + .on_chip = 0, + .xtal = R8A66597_PLATDATA_XTAL_48MHZ, +}; + +static struct resource usb_resources[] = { + [0] = { + .start = 0x10010000, + .end = 0x1001ffff - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = intcs_evt2irq(0x220), /* IRQ1 */ + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device usb_host_device = { + .name = "r8a66597_hcd", + .dev = { + .platform_data = &usb_host_data, + .dma_mask = NULL, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(usb_resources), + .resource = usb_resources, +}; + +/* LCDC */ +static struct fb_videomode kzm_lcdc_mode = { + .name = "WVGA Panel", + .xres = 800, + .yres = 480, + .left_margin = 220, + .right_margin = 110, + .hsync_len = 70, + .upper_margin = 20, + .lower_margin = 5, + .vsync_len = 5, + .sync = 0, +}; + +static struct sh_mobile_lcdc_info lcdc_info = { + .clock_source = LCDC_CLK_BUS, + .ch[0] = { + .chan = LCDC_CHAN_MAINLCD, + .fourcc = V4L2_PIX_FMT_RGB565, + .interface_type = RGB24, + .lcd_modes = &kzm_lcdc_mode, + .num_modes = 1, + .clock_divider = 5, + .flags = 0, + .panel_cfg = { + .width = 152, + .height = 91, + }, + } +}; + +static struct resource lcdc_resources[] = { + [0] = { + .name = "LCDC", + .start = 0xfe940000, + .end = 0xfe943fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = intcs_evt2irq(0x580), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device lcdc_device = { + .name = "sh_mobile_lcdc_fb", + .num_resources = ARRAY_SIZE(lcdc_resources), + .resource = lcdc_resources, + .dev = { + .platform_data = &lcdc_info, + .coherent_dma_mask = ~0, + }, +}; + +/* MMCIF */ +static struct resource sh_mmcif_resources[] = { + [0] = { + .name = "MMCIF", + .start = 0xe6bd0000, + .end = 0xe6bd00ff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = gic_spi(141), + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = gic_spi(140), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct sh_mmcif_plat_data sh_mmcif_platdata = { + .ocr = MMC_VDD_165_195, + .caps = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE, +}; + +static struct platform_device mmc_device = { + .name = "sh_mmcif", + .dev = { + .dma_mask = NULL, + .coherent_dma_mask = 0xffffffff, + .platform_data = &sh_mmcif_platdata, + }, + .num_resources = ARRAY_SIZE(sh_mmcif_resources), + .resource = sh_mmcif_resources, +}; + +/* SDHI */ +static struct sh_mobile_sdhi_info sdhi0_info = { + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT, + .tmio_caps = MMC_CAP_SD_HIGHSPEED, + .tmio_ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29, +}; + +static struct resource sdhi0_resources[] = { + [0] = { + .name = "SDHI0", + .start = 0xee100000, + .end = 0xee1000ff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = SH_MOBILE_SDHI_IRQ_CARD_DETECT, + .start = gic_spi(83), + .flags = IORESOURCE_IRQ, + }, + [2] = { + .name = SH_MOBILE_SDHI_IRQ_SDCARD, + .start = gic_spi(84), + .flags = IORESOURCE_IRQ, + }, + [3] = { + .name = SH_MOBILE_SDHI_IRQ_SDIO, + .start = gic_spi(85), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device sdhi0_device = { + .name = "sh_mobile_sdhi", + .num_resources = ARRAY_SIZE(sdhi0_resources), + .resource = sdhi0_resources, + .dev = { + .platform_data = &sdhi0_info, + }, +}; + +/* KEY */ +#define GPIO_KEY(c, g, d) { .code = c, .gpio = g, .desc = d, .active_low = 1 } + +static struct gpio_keys_button gpio_buttons[] = { + GPIO_KEY(KEY_BACK, GPIO_PCF8575_PORT10, "SW3"), + GPIO_KEY(KEY_RIGHT, GPIO_PCF8575_PORT11, "SW2-R"), + GPIO_KEY(KEY_LEFT, GPIO_PCF8575_PORT12, "SW2-L"), + GPIO_KEY(KEY_ENTER, GPIO_PCF8575_PORT13, "SW2-P"), + GPIO_KEY(KEY_UP, GPIO_PCF8575_PORT14, "SW2-U"), + GPIO_KEY(KEY_DOWN, GPIO_PCF8575_PORT15, "SW2-D"), + GPIO_KEY(KEY_HOME, GPIO_PCF8575_PORT16, "SW1"), +}; + +static struct gpio_keys_platform_data gpio_key_info = { + .buttons = gpio_buttons, + .nbuttons = ARRAY_SIZE(gpio_buttons), + .poll_interval = 250, /* poling at this point */ +}; + +static struct platform_device gpio_keys_device = { + /* gpio-pcf857x.c driver doesn't support gpio_to_irq() */ + .name = "gpio-keys-polled", + .dev = { + .platform_data = &gpio_key_info, + }, +}; + +/* I2C */ +static struct pcf857x_platform_data pcf8575_pdata = { + .gpio_base = GPIO_PCF8575_BASE, +}; + +static struct i2c_board_info i2c1_devices[] = { + { + I2C_BOARD_INFO("st1232-ts", 0x55), + .irq = intcs_evt2irq(0x300), /* IRQ8 */ + }, +}; + +static struct i2c_board_info i2c3_devices[] = { + { + I2C_BOARD_INFO("pcf8575", 0x20), + .platform_data = &pcf8575_pdata, + }, +}; + +static struct platform_device *kzm_devices[] __initdata = { + &smsc_device, + &usb_host_device, + &lcdc_device, + &mmc_device, + &sdhi0_device, + &gpio_keys_device, +}; + +/* + * FIXME + * + * This is quick hack for enabling LCDC backlight + */ +static int __init as3711_enable_lcdc_backlight(void) +{ + struct i2c_adapter *a = i2c_get_adapter(0); + struct i2c_msg msg; + int i, ret; + __u8 magic[] = { + 0x40, 0x2a, + 0x43, 0x3c, + 0x44, 0x3c, + 0x45, 0x3c, + 0x54, 0x03, + 0x51, 0x00, + 0x51, 0x01, + 0xff, 0x00, /* wait */ + 0x43, 0xf0, + 0x44, 0xf0, + 0x45, 0xf0, + }; + + if (!machine_is_kzm9g()) + return 0; + + if (!a) + return 0; + + msg.addr = 0x40; + msg.len = 2; + msg.flags = 0; + + for (i = 0; i < ARRAY_SIZE(magic); i += 2) { + msg.buf = magic + i; + + if (0xff == msg.buf[0]) { + udelay(500); + continue; + } + + ret = i2c_transfer(a, &msg, 1); + if (ret < 0) { + pr_err("i2c transfer fail\n"); + break; + } + } + + return 0; +} +device_initcall(as3711_enable_lcdc_backlight); + +static void __init kzm_init(void) +{ + sh73a0_pinmux_init(); + + /* enable SCIFA4 */ + gpio_request(GPIO_FN_SCIFA4_TXD, NULL); + gpio_request(GPIO_FN_SCIFA4_RXD, NULL); + gpio_request(GPIO_FN_SCIFA4_RTS_, NULL); + gpio_request(GPIO_FN_SCIFA4_CTS_, NULL); + + /* CS4 for SMSC/USB */ + gpio_request(GPIO_FN_CS4_, NULL); /* CS4 */ + + /* SMSC */ + gpio_request(GPIO_PORT224, NULL); /* IRQ3 */ + gpio_direction_input(GPIO_PORT224); + + /* LCDC */ + gpio_request(GPIO_FN_LCDD23, NULL); + gpio_request(GPIO_FN_LCDD22, NULL); + gpio_request(GPIO_FN_LCDD21, NULL); + gpio_request(GPIO_FN_LCDD20, NULL); + gpio_request(GPIO_FN_LCDD19, NULL); + gpio_request(GPIO_FN_LCDD18, NULL); + gpio_request(GPIO_FN_LCDD17, NULL); + gpio_request(GPIO_FN_LCDD16, NULL); + gpio_request(GPIO_FN_LCDD15, NULL); + gpio_request(GPIO_FN_LCDD14, NULL); + gpio_request(GPIO_FN_LCDD13, NULL); + gpio_request(GPIO_FN_LCDD12, NULL); + gpio_request(GPIO_FN_LCDD11, NULL); + gpio_request(GPIO_FN_LCDD10, NULL); + gpio_request(GPIO_FN_LCDD9, NULL); + gpio_request(GPIO_FN_LCDD8, NULL); + gpio_request(GPIO_FN_LCDD7, NULL); + gpio_request(GPIO_FN_LCDD6, NULL); + gpio_request(GPIO_FN_LCDD5, NULL); + gpio_request(GPIO_FN_LCDD4, NULL); + gpio_request(GPIO_FN_LCDD3, NULL); + gpio_request(GPIO_FN_LCDD2, NULL); + gpio_request(GPIO_FN_LCDD1, NULL); + gpio_request(GPIO_FN_LCDD0, NULL); + gpio_request(GPIO_FN_LCDDISP, NULL); + gpio_request(GPIO_FN_LCDDCK, NULL); + + gpio_request(GPIO_PORT222, NULL); /* LCDCDON */ + gpio_request(GPIO_PORT226, NULL); /* SC */ + gpio_direction_output(GPIO_PORT222, 1); + gpio_direction_output(GPIO_PORT226, 1); + + /* Touchscreen */ + gpio_request(GPIO_PORT223, NULL); /* IRQ8 */ + gpio_direction_input(GPIO_PORT223); + + /* enable MMCIF */ + gpio_request(GPIO_FN_MMCCLK0, NULL); + gpio_request(GPIO_FN_MMCCMD0_PU, NULL); + gpio_request(GPIO_FN_MMCD0_0_PU, NULL); + gpio_request(GPIO_FN_MMCD0_1_PU, NULL); + gpio_request(GPIO_FN_MMCD0_2_PU, NULL); + gpio_request(GPIO_FN_MMCD0_3_PU, NULL); + gpio_request(GPIO_FN_MMCD0_4_PU, NULL); + gpio_request(GPIO_FN_MMCD0_5_PU, NULL); + gpio_request(GPIO_FN_MMCD0_6_PU, NULL); + gpio_request(GPIO_FN_MMCD0_7_PU, NULL); + + /* enable SD */ + gpio_request(GPIO_FN_SDHIWP0, NULL); + gpio_request(GPIO_FN_SDHICD0, NULL); + gpio_request(GPIO_FN_SDHICMD0, NULL); + gpio_request(GPIO_FN_SDHICLK0, NULL); + gpio_request(GPIO_FN_SDHID0_3, NULL); + gpio_request(GPIO_FN_SDHID0_2, NULL); + gpio_request(GPIO_FN_SDHID0_1, NULL); + gpio_request(GPIO_FN_SDHID0_0, NULL); + gpio_request(GPIO_FN_SDHI0_VCCQ_MC0_ON, NULL); + gpio_request(GPIO_PORT15, NULL); + gpio_direction_output(GPIO_PORT15, 1); /* power */ + + /* I2C 3 */ + gpio_request(GPIO_FN_PORT27_I2C_SCL3, NULL); + gpio_request(GPIO_FN_PORT28_I2C_SDA3, NULL); + +#ifdef CONFIG_CACHE_L2X0 + /* Early BRESP enable, Shared attribute override enable, 64K*8way */ + l2x0_init(IOMEM(0xf0100000), 0x40460000, 0x82000fff); +#endif + + i2c_register_board_info(1, i2c1_devices, ARRAY_SIZE(i2c1_devices)); + i2c_register_board_info(3, i2c3_devices, ARRAY_SIZE(i2c3_devices)); + + sh73a0_add_standard_devices(); + platform_add_devices(kzm_devices, ARRAY_SIZE(kzm_devices)); +} + +static const char *kzm9g_boards_compat_dt[] __initdata = { + "renesas,kzm9g", + NULL, +}; + +DT_MACHINE_START(KZM9G_DT, "kzm9g") + .map_io = sh73a0_map_io, + .init_early = sh73a0_add_early_devices, + .nr_irqs = NR_IRQS_LEGACY, + .init_irq = sh73a0_init_irq, + .handle_irq = gic_handle_irq, + .init_machine = kzm_init, + .timer = &shmobile_timer, + .dt_compat = kzm9g_boards_compat_dt, +MACHINE_END diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 8c6202bb6aeb..aae2e24fde46 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -908,6 +908,8 @@ fsi_set_rate_end: static struct sh_fsi_platform_info fsi_info = { .port_a = { .flags = SH_FSI_BRS_INV, + .tx_id = SHDMA_SLAVE_FSIA_TX, + .rx_id = SHDMA_SLAVE_FSIA_RX, }, .port_b = { .flags = SH_FSI_BRS_INV | @@ -920,9 +922,11 @@ static struct sh_fsi_platform_info fsi_info = { static struct resource fsi_resources[] = { [0] = { + /* we need 0xFE1F0000 to access DMA + * instead of 0xFE3C0000 */ .name = "FSI", - .start = 0xFE3C0000, - .end = 0xFE3C0400 - 1, + .start = 0xFE1F0000, + .end = 0xFE1F0400 - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -1248,6 +1252,8 @@ static void mackerel_camera_del(struct soc_camera_device *icd) static struct sh_mobile_ceu_info sh_mobile_ceu_info = { .flags = SH_CEU_FLAG_USE_8BIT_BUS, + .max_width = 8188, + .max_height = 8188, }; static struct resource ceu_resources[] = { diff --git a/arch/arm/mach-shmobile/clock-emev2.c b/arch/arm/mach-shmobile/clock-emev2.c new file mode 100644 index 000000000000..4710f1847bb7 --- /dev/null +++ b/arch/arm/mach-shmobile/clock-emev2.c @@ -0,0 +1,249 @@ +/* + * Emma Mobile EV2 clock framework support + * + * Copyright (C) 2012 Magnus Damm + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * 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/init.h> +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/sh_clk.h> +#include <linux/clkdev.h> +#include <mach/common.h> + +#define EMEV2_SMU_BASE 0xe0110000 + +/* EMEV2 SMU registers */ +#define USIAU0_RSTCTRL 0x094 +#define USIBU1_RSTCTRL 0x0ac +#define USIBU2_RSTCTRL 0x0b0 +#define USIBU3_RSTCTRL 0x0b4 +#define STI_RSTCTRL 0x124 +#define USIAU0GCLKCTRL 0x4a0 +#define USIBU1GCLKCTRL 0x4b8 +#define USIBU2GCLKCTRL 0x4bc +#define USIBU3GCLKCTRL 0x04c0 +#define STIGCLKCTRL 0x528 +#define USIAU0SCLKDIV 0x61c +#define USIB2SCLKDIV 0x65c +#define USIB3SCLKDIV 0x660 +#define STI_CLKSEL 0x688 +#define SMU_GENERAL_REG0 0x7c0 + +/* not pretty, but hey */ +static void __iomem *smu_base; + +static void emev2_smu_write(unsigned long value, int offs) +{ + BUG_ON(!smu_base || (offs >= PAGE_SIZE)); + iowrite32(value, smu_base + offs); +} + +void emev2_set_boot_vector(unsigned long value) +{ + emev2_smu_write(value, SMU_GENERAL_REG0); +} + +static struct clk_mapping smu_mapping = { + .phys = EMEV2_SMU_BASE, + .len = PAGE_SIZE, +}; + +/* Fixed 32 KHz root clock from C32K pin */ +static struct clk c32k_clk = { + .rate = 32768, + .mapping = &smu_mapping, +}; + +/* PLL3 multiplies C32K with 7000 */ +static unsigned long pll3_recalc(struct clk *clk) +{ + return clk->parent->rate * 7000; +} + +static struct sh_clk_ops pll3_clk_ops = { + .recalc = pll3_recalc, +}; + +static struct clk pll3_clk = { + .ops = &pll3_clk_ops, + .parent = &c32k_clk, +}; + +static struct clk *main_clks[] = { + &c32k_clk, + &pll3_clk, +}; + +enum { SCLKDIV_USIAU0, SCLKDIV_USIBU2, SCLKDIV_USIBU1, SCLKDIV_USIBU3, + SCLKDIV_NR }; + +#define SCLKDIV(_reg, _shift) \ +{ \ + .parent = &pll3_clk, \ + .enable_reg = IOMEM(EMEV2_SMU_BASE + (_reg)), \ + .enable_bit = _shift, \ +} + +static struct clk sclkdiv_clks[SCLKDIV_NR] = { + [SCLKDIV_USIAU0] = SCLKDIV(USIAU0SCLKDIV, 0), + [SCLKDIV_USIBU2] = SCLKDIV(USIB2SCLKDIV, 16), + [SCLKDIV_USIBU1] = SCLKDIV(USIB2SCLKDIV, 0), + [SCLKDIV_USIBU3] = SCLKDIV(USIB3SCLKDIV, 0), +}; + +enum { GCLK_USIAU0_SCLK, GCLK_USIBU1_SCLK, GCLK_USIBU2_SCLK, GCLK_USIBU3_SCLK, + GCLK_STI_SCLK, + GCLK_NR }; + +#define GCLK_SCLK(_parent, _reg) \ +{ \ + .parent = _parent, \ + .enable_reg = IOMEM(EMEV2_SMU_BASE + (_reg)), \ + .enable_bit = 1, /* SCLK_GCC */ \ +} + +static struct clk gclk_clks[GCLK_NR] = { + [GCLK_USIAU0_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIAU0], + USIAU0GCLKCTRL), + [GCLK_USIBU1_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU1], + USIBU1GCLKCTRL), + [GCLK_USIBU2_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU2], + USIBU2GCLKCTRL), + [GCLK_USIBU3_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU3], + USIBU3GCLKCTRL), + [GCLK_STI_SCLK] = GCLK_SCLK(&c32k_clk, STIGCLKCTRL), +}; + +static int emev2_gclk_enable(struct clk *clk) +{ + iowrite32(ioread32(clk->mapped_reg) | (1 << clk->enable_bit), + clk->mapped_reg); + return 0; +} + +static void emev2_gclk_disable(struct clk *clk) +{ + iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit), + clk->mapped_reg); +} + +static struct sh_clk_ops emev2_gclk_clk_ops = { + .enable = emev2_gclk_enable, + .disable = emev2_gclk_disable, + .recalc = followparent_recalc, +}; + +static int __init emev2_gclk_register(struct clk *clks, int nr) +{ + struct clk *clkp; + int ret = 0; + int k; + + for (k = 0; !ret && (k < nr); k++) { + clkp = clks + k; + clkp->ops = &emev2_gclk_clk_ops; + ret |= clk_register(clkp); + } + + return ret; +} + +static unsigned long emev2_sclkdiv_recalc(struct clk *clk) +{ + unsigned int sclk_div; + + sclk_div = (ioread32(clk->mapped_reg) >> clk->enable_bit) & 0xff; + + return clk->parent->rate / (sclk_div + 1); +} + +static struct sh_clk_ops emev2_sclkdiv_clk_ops = { + .recalc = emev2_sclkdiv_recalc, +}; + +static int __init emev2_sclkdiv_register(struct clk *clks, int nr) +{ + struct clk *clkp; + int ret = 0; + int k; + + for (k = 0; !ret && (k < nr); k++) { + clkp = clks + k; + clkp->ops = &emev2_sclkdiv_clk_ops; + ret |= clk_register(clkp); + } + + return ret; +} + +static struct clk_lookup lookups[] = { + CLKDEV_DEV_ID("serial8250-em.0", &gclk_clks[GCLK_USIAU0_SCLK]), + CLKDEV_DEV_ID("e1020000.uart", &gclk_clks[GCLK_USIAU0_SCLK]), + CLKDEV_DEV_ID("serial8250-em.1", &gclk_clks[GCLK_USIBU1_SCLK]), + CLKDEV_DEV_ID("e1030000.uart", &gclk_clks[GCLK_USIBU1_SCLK]), + CLKDEV_DEV_ID("serial8250-em.2", &gclk_clks[GCLK_USIBU2_SCLK]), + CLKDEV_DEV_ID("e1040000.uart", &gclk_clks[GCLK_USIBU2_SCLK]), + CLKDEV_DEV_ID("serial8250-em.3", &gclk_clks[GCLK_USIBU3_SCLK]), + CLKDEV_DEV_ID("e1050000.uart", &gclk_clks[GCLK_USIBU3_SCLK]), + CLKDEV_DEV_ID("em_sti.0", &gclk_clks[GCLK_STI_SCLK]), + CLKDEV_DEV_ID("e0180000.sti", &gclk_clks[GCLK_STI_SCLK]), +}; + +void __init emev2_clock_init(void) +{ + int k, ret = 0; + static int is_setup; + + /* yuck, this is ugly as hell, but the non-smp case of clocks + * code is now designed to rely on ioremap() instead of static + * entity maps. in the case of smp we need access to the SMU + * register earlier than ioremap() is actually working without + * any static maps. to enable SMP in ugly but with dynamic + * mappings we have to call emev2_clock_init() from different + * places depending on UP and SMP... + */ + if (is_setup++) + return; + + smu_base = ioremap(EMEV2_SMU_BASE, PAGE_SIZE); + BUG_ON(!smu_base); + + /* setup STI timer to run on 37.768 kHz and deassert reset */ + emev2_smu_write(0, STI_CLKSEL); + emev2_smu_write(1, STI_RSTCTRL); + + /* deassert reset for UART0->UART3 */ + emev2_smu_write(2, USIAU0_RSTCTRL); + emev2_smu_write(2, USIBU1_RSTCTRL); + emev2_smu_write(2, USIBU2_RSTCTRL); + emev2_smu_write(2, USIBU3_RSTCTRL); + + for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++) + ret = clk_register(main_clks[k]); + + if (!ret) + ret = emev2_sclkdiv_register(sclkdiv_clks, SCLKDIV_NR); + + if (!ret) + ret = emev2_gclk_register(gclk_clks, GCLK_NR); + + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); + + if (!ret) + shmobile_clk_init(); + else + panic("failed to setup emev2 clocks\n"); +} diff --git a/arch/arm/mach-shmobile/clock-r8a7740.c b/arch/arm/mach-shmobile/clock-r8a7740.c index 99c4d743a99c..26eea5f21054 100644 --- a/arch/arm/mach-shmobile/clock-r8a7740.c +++ b/arch/arm/mach-shmobile/clock-r8a7740.c @@ -47,6 +47,7 @@ #define PLLC01CR 0xe6150028 #define SUBCKCR 0xe6150080 +#define USBCKCR 0xe615008c #define MSTPSR0 0xe6150030 #define MSTPSR1 0xe6150038 @@ -181,6 +182,95 @@ static struct clk pllc1_div2_clk = { .parent = &pllc1_clk, }; +/* USB clock */ +static struct clk *usb24s_parents[] = { + [0] = &system_clk, + [1] = &extal2_clk +}; + +static int usb24s_enable(struct clk *clk) +{ + __raw_writel(__raw_readl(USBCKCR) & ~(1 << 8), USBCKCR); + + return 0; +} + +static void usb24s_disable(struct clk *clk) +{ + __raw_writel(__raw_readl(USBCKCR) | (1 << 8), USBCKCR); +} + +static int usb24s_set_parent(struct clk *clk, struct clk *parent) +{ + int i, ret; + u32 val; + + if (!clk->parent_table || !clk->parent_num) + return -EINVAL; + + /* Search the parent */ + for (i = 0; i < clk->parent_num; i++) + if (clk->parent_table[i] == parent) + break; + + if (i == clk->parent_num) + return -ENODEV; + + ret = clk_reparent(clk, parent); + if (ret < 0) + return ret; + + val = __raw_readl(USBCKCR); + val &= ~(1 << 7); + val |= i << 7; + __raw_writel(val, USBCKCR); + + return 0; +} + +static struct sh_clk_ops usb24s_clk_ops = { + .recalc = followparent_recalc, + .enable = usb24s_enable, + .disable = usb24s_disable, + .set_parent = usb24s_set_parent, +}; + +static struct clk usb24s_clk = { + .ops = &usb24s_clk_ops, + .parent_table = usb24s_parents, + .parent_num = ARRAY_SIZE(usb24s_parents), + .parent = &system_clk, +}; + +static unsigned long usb24_recalc(struct clk *clk) +{ + return clk->parent->rate / + ((__raw_readl(USBCKCR) & (1 << 6)) ? 1 : 2); +}; + +static int usb24_set_rate(struct clk *clk, unsigned long rate) +{ + u32 val; + + /* closer to which ? parent->rate or parent->rate/2 */ + val = __raw_readl(USBCKCR); + val &= ~(1 << 6); + val |= (rate > (clk->parent->rate / 4) * 3) << 6; + __raw_writel(val, USBCKCR); + + return 0; +} + +static struct sh_clk_ops usb24_clk_ops = { + .recalc = usb24_recalc, + .set_rate = usb24_set_rate, +}; + +static struct clk usb24_clk = { + .ops = &usb24_clk_ops, + .parent = &usb24s_clk, +}; + struct clk *main_clks[] = { &extalr_clk, &extal1_clk, @@ -196,6 +286,8 @@ struct clk *main_clks[] = { &pllc0_clk, &pllc1_clk, &pllc1_div2_clk, + &usb24s_clk, + &usb24_clk, }; static void div4_kick(struct clk *clk) @@ -223,7 +315,7 @@ static struct clk_div4_table div4_table = { enum { DIV4_I, DIV4_ZG, DIV4_B, DIV4_M1, DIV4_HP, - DIV4_HPP, DIV4_S, DIV4_ZB, DIV4_M3, DIV4_CP, + DIV4_HPP, DIV4_USBP, DIV4_S, DIV4_ZB, DIV4_M3, DIV4_CP, DIV4_NR }; @@ -234,6 +326,7 @@ struct clk div4_clks[DIV4_NR] = { [DIV4_M1] = SH_CLK_DIV4(&pllc1_clk, FRQCRA, 4, 0x6fff, CLK_ENABLE_ON_INIT), [DIV4_HP] = SH_CLK_DIV4(&pllc1_clk, FRQCRB, 4, 0x6fff, 0), [DIV4_HPP] = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 20, 0x6fff, 0), + [DIV4_USBP] = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 16, 0x6fff, 0), [DIV4_S] = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 12, 0x6fff, 0), [DIV4_ZB] = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 8, 0x6fff, 0), [DIV4_M3] = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 4, 0x6fff, 0), @@ -257,7 +350,11 @@ enum { MSTP222, MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200, - MSTP329, MSTP323, + MSTP329, MSTP328, MSTP323, MSTP320, + MSTP314, MSTP313, MSTP312, + MSTP309, + + MSTP416, MSTP415, MSTP407, MSTP406, MSTP_NR }; @@ -280,7 +377,18 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP200] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */ [MSTP329] = SH_CLK_MSTP32(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */ + [MSTP328] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR3, 28, 0), /* FSI */ [MSTP323] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */ + [MSTP320] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR3, 20, 0), /* USBF */ + [MSTP314] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR3, 14, 0), /* SDHI0 */ + [MSTP313] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR3, 13, 0), /* SDHI1 */ + [MSTP312] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMC */ + [MSTP309] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR3, 9, 0), /* GEther */ + + [MSTP416] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR4, 16, 0), /* USBHOST */ + [MSTP415] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR4, 15, 0), /* SDHI2 */ + [MSTP407] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR4, 7, 0), /* USB-Func */ + [MSTP406] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR4, 6, 0), /* USB Phy */ }; static struct clk_lookup lookups[] = { @@ -299,6 +407,7 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("pllc0_clk", &pllc0_clk), CLKDEV_CON_ID("pllc1_clk", &pllc1_clk), CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk), + CLKDEV_CON_ID("usb24s", &usb24s_clk), /* DIV4 clocks */ CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]), @@ -334,7 +443,22 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP230]), CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), + CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), + CLKDEV_DEV_ID("renesas_usbhs", &mstp_clks[MSTP320]), + CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), + CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), + CLKDEV_DEV_ID("sh_mmcif", &mstp_clks[MSTP312]), + CLKDEV_DEV_ID("sh-eth", &mstp_clks[MSTP309]), + + CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP415]), + + /* ICK */ + CLKDEV_ICK_ID("host", "renesas_usbhs", &mstp_clks[MSTP416]), + CLKDEV_ICK_ID("func", "renesas_usbhs", &mstp_clks[MSTP407]), + CLKDEV_ICK_ID("phy", "renesas_usbhs", &mstp_clks[MSTP406]), + CLKDEV_ICK_ID("pci", "renesas_usbhs", &div4_clks[DIV4_USBP]), + CLKDEV_ICK_ID("usb24", "renesas_usbhs", &usb24_clk), }; void __init r8a7740_clock_init(u8 md_ck) diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index c85e6ecda606..ff5f12fd742f 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -3,6 +3,8 @@ extern void shmobile_earlytimer_init(void); extern struct sys_timer shmobile_timer; +extern void shmobile_setup_delay(unsigned int max_cpu_core_mhz, + unsigned int mult, unsigned int div); struct twd_local_timer; extern void shmobile_setup_console(void); extern void shmobile_secondary_vector(void); diff --git a/arch/arm/mach-shmobile/include/mach/emev2.h b/arch/arm/mach-shmobile/include/mach/emev2.h new file mode 100644 index 000000000000..e6b0c1bf4b7e --- /dev/null +++ b/arch/arm/mach-shmobile/include/mach/emev2.h @@ -0,0 +1,19 @@ +#ifndef __ASM_EMEV2_H__ +#define __ASM_EMEV2_H__ + +extern void emev2_map_io(void); +extern void emev2_init_irq(void); +extern void emev2_add_early_devices(void); +extern void emev2_add_standard_devices(void); +extern void emev2_clock_init(void); +extern void emev2_set_boot_vector(unsigned long value); +extern unsigned int emev2_get_core_count(void); +extern int emev2_platform_cpu_kill(unsigned int cpu); +extern void emev2_secondary_init(unsigned int cpu); +extern int emev2_boot_secondary(unsigned int cpu); +extern void emev2_smp_prepare_cpus(void); + +#define EMEV2_GPIO_BASE 200 +#define EMEV2_GPIO_IRQ(n) (EMEV2_GPIO_BASE + (n)) + +#endif /* __ASM_EMEV2_H__ */ diff --git a/arch/arm/mach-shmobile/include/mach/intc.h b/arch/arm/mach-shmobile/include/mach/intc.h index 8b22258c8caa..a5603c76cfe0 100644 --- a/arch/arm/mach-shmobile/include/mach/intc.h +++ b/arch/arm/mach-shmobile/include/mach/intc.h @@ -142,6 +142,50 @@ static struct intc_desc p ## _desc __initdata = { \ p ## _sense_registers, p ## _ack_registers) \ } +#define INTC_IRQ_PINS_16H(p, base, vect, str) \ + \ +static struct resource p ## _resources[] __initdata = { \ + [0] = { \ + .start = base, \ + .end = base + 0x64, \ + .flags = IORESOURCE_MEM, \ + }, \ +}; \ + \ +enum { \ + p ## _UNUSED = 0, \ + INTC_IRQ_PINS_ENUM_16H(p), \ +}; \ + \ +static struct intc_vect p ## _vectors[] __initdata = { \ + INTC_IRQ_PINS_VECT_16H(p, vect), \ +}; \ + \ +static struct intc_mask_reg p ## _mask_registers[] __initdata = { \ + INTC_IRQ_PINS_MASK_16H(p, base), \ +}; \ + \ +static struct intc_prio_reg p ## _prio_registers[] __initdata = { \ + INTC_IRQ_PINS_PRIO_16H(p, base), \ +}; \ + \ +static struct intc_sense_reg p ## _sense_registers[] __initdata = { \ + INTC_IRQ_PINS_SENSE_16H(p, base), \ +}; \ + \ +static struct intc_mask_reg p ## _ack_registers[] __initdata = { \ + INTC_IRQ_PINS_ACK_16H(p, base), \ +}; \ + \ +static struct intc_desc p ## _desc __initdata = { \ + .name = str, \ + .resource = p ## _resources, \ + .num_resources = ARRAY_SIZE(p ## _resources), \ + .hw = INTC_HW_DESC(p ## _vectors, NULL, \ + p ## _mask_registers, p ## _prio_registers, \ + p ## _sense_registers, p ## _ack_registers) \ +} + #define INTC_IRQ_PINS_32(p, base, vect, str) \ \ static struct resource p ## _resources[] __initdata = { \ diff --git a/arch/arm/mach-shmobile/include/mach/irqs.h b/arch/arm/mach-shmobile/include/mach/irqs.h index 4e686cc201fc..06a5da3c3050 100644 --- a/arch/arm/mach-shmobile/include/mach/irqs.h +++ b/arch/arm/mach-shmobile/include/mach/irqs.h @@ -7,7 +7,7 @@ #define gic_spi(nr) ((nr) + 32) /* INTCS */ -#define INTCS_VECT_BASE 0x2200 +#define INTCS_VECT_BASE 0x3400 #define INTCS_VECT(n, vect) INTC_VECT((n), INTCS_VECT_BASE + (vect)) #define intcs_evt2irq(evt) evt2irq(INTCS_VECT_BASE + (evt)) diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h index 8254ab86f6cd..915d0093da08 100644 --- a/arch/arm/mach-shmobile/include/mach/sh7372.h +++ b/arch/arm/mach-shmobile/include/mach/sh7372.h @@ -457,6 +457,8 @@ enum { SHDMA_SLAVE_SDHI1_TX, SHDMA_SLAVE_SDHI2_RX, SHDMA_SLAVE_SDHI2_TX, + SHDMA_SLAVE_FSIA_RX, + SHDMA_SLAVE_FSIA_TX, SHDMA_SLAVE_MMCIF_RX, SHDMA_SLAVE_MMCIF_TX, SHDMA_SLAVE_USB0_TX, diff --git a/arch/arm/mach-shmobile/include/mach/sh73a0.h b/arch/arm/mach-shmobile/include/mach/sh73a0.h index cad57578ceed..398e2c10913b 100644 --- a/arch/arm/mach-shmobile/include/mach/sh73a0.h +++ b/arch/arm/mach-shmobile/include/mach/sh73a0.h @@ -482,6 +482,9 @@ enum { GPIO_FN_FSIAILR_PU, GPIO_FN_FSIAIBT_PU, GPIO_FN_FSIAISLD_PU, + + /* end of GPIO */ + GPIO_NR, }; /* DMA slave IDs */ @@ -515,8 +518,36 @@ enum { SHDMA_SLAVE_MMCIF_RX, }; -/* PINT interrupts are located at Linux IRQ 800 and up */ -#define SH73A0_PINT0_IRQ(irq) ((irq) + 800) -#define SH73A0_PINT1_IRQ(irq) ((irq) + 832) +/* + * SH73A0 IRQ LOCATION TABLE + * + * 416 ----------------------------------------- + * IRQ0-IRQ15 + * 431 ----------------------------------------- + * ... + * 448 ----------------------------------------- + * sh73a0-intcs + * sh73a0-intca-irq-pins + * 680 ----------------------------------------- + * ... + * 700 ----------------------------------------- + * sh73a0-pint0 + * 731 ----------------------------------------- + * 732 ----------------------------------------- + * sh73a0-pint1 + * 739 ----------------------------------------- + * ... + * 800 ----------------------------------------- + * IRQ16-IRQ31 + * 815 ----------------------------------------- + * ... + * 928 ----------------------------------------- + * sh73a0-intca-irq-pins + * 943 ----------------------------------------- + */ + +/* PINT interrupts are located at Linux IRQ 700 and up */ +#define SH73A0_PINT0_IRQ(irq) ((irq) + 700) +#define SH73A0_PINT1_IRQ(irq) ((irq) + 732) #endif /* __ASM_SH73A0_H__ */ diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c index 6447e0af52d4..2587a22842f2 100644 --- a/arch/arm/mach-shmobile/intc-sh7372.c +++ b/arch/arm/mach-shmobile/intc-sh7372.c @@ -19,6 +19,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <linux/irq.h> #include <linux/io.h> #include <linux/sh_intc.h> @@ -305,14 +306,16 @@ static DECLARE_INTC_DESC(intca_desc, "sh7372-intca", intca_mask_registers, intca_prio_registers, NULL); -INTC_IRQ_PINS_32(intca_irq_pins, 0xe6900000, - INTC_VECT, "sh7372-intca-irq-pins"); +INTC_IRQ_PINS_16(intca_irq_pins_lo, 0xe6900000, + INTC_VECT, "sh7372-intca-irq-lo"); + +INTC_IRQ_PINS_16H(intca_irq_pins_hi, 0xe6900000, + INTC_VECT, "sh7372-intca-irq-hi"); + enum { UNUSED_INTCS = 0, ENABLED_INTCS, - INTCS, - /* interrupt sources INTCS */ /* IRQ0S - IRQ31S */ @@ -426,8 +429,6 @@ static struct intc_vect intcs_vectors[] = { INTCS_VECT(CPORTS2R, 0x1a20), /* CEC */ INTCS_VECT(JPU6E, 0x1a80), - - INTC_VECT(INTCS, 0xf80), }; static struct intc_group intcs_groups[] __initdata = { @@ -490,9 +491,6 @@ static struct intc_mask_reg intcs_mask_registers[] = { { 0xffd5019c, 0xffd501dc, 8, /* IMR7SA3 / IMCR7SA3 */ { MFIS2_INTCS, CPORTS2R, 0, 0, JPU6E, 0, 0, 0 } }, - { 0xffd20104, 0, 16, /* INTAMASK */ - { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, INTCS } }, }; /* Priority is needed for INTCA to receive the INTCS interrupt */ @@ -557,18 +555,30 @@ static void __iomem *intcs_ffd5; void __init sh7372_init_irq(void) { void __iomem *intevtsa; + int n; intcs_ffd2 = ioremap_nocache(0xffd20000, PAGE_SIZE); intevtsa = intcs_ffd2 + 0x100; intcs_ffd5 = ioremap_nocache(0xffd50000, PAGE_SIZE); register_intc_controller(&intca_desc); - register_intc_controller(&intca_irq_pins_desc); + register_intc_controller(&intca_irq_pins_lo_desc); + register_intc_controller(&intca_irq_pins_hi_desc); register_intc_controller(&intcs_desc); + /* setup dummy cascade chip for INTCS */ + n = evt2irq(0xf80); + irq_alloc_desc_at(n, numa_node_id()); + irq_set_chip_and_handler_name(n, &dummy_irq_chip, + handle_level_irq, "level"); + set_irq_flags(n, IRQF_VALID); /* yuck */ + /* demux using INTEVTSA */ - irq_set_handler_data(evt2irq(0xf80), (void *)intevtsa); - irq_set_chained_handler(evt2irq(0xf80), intcs_demux); + irq_set_handler_data(n, (void *)intevtsa); + irq_set_chained_handler(n, intcs_demux); + + /* unmask INTCS in INTAMASK */ + iowrite16(0, intcs_ffd2 + 0x104); } static unsigned short ffd2[0x200]; diff --git a/arch/arm/mach-shmobile/pfc-r8a7740.c b/arch/arm/mach-shmobile/pfc-r8a7740.c index a4fff6950b03..670fe1869dbc 100644 --- a/arch/arm/mach-shmobile/pfc-r8a7740.c +++ b/arch/arm/mach-shmobile/pfc-r8a7740.c @@ -22,6 +22,7 @@ #include <linux/kernel.h> #include <linux/gpio.h> #include <mach/r8a7740.h> +#include <mach/irqs.h> #define CPU_ALL_PORT(fn, pfx, sfx) \ PORT_10(fn, pfx, sfx), PORT_90(fn, pfx, sfx), \ @@ -2527,6 +2528,41 @@ static struct pinmux_data_reg pinmux_data_regs[] = { { }, }; +static struct pinmux_irq pinmux_irqs[] = { + PINMUX_IRQ(evt2irq(0x0200), PORT2_FN0, PORT13_FN0), /* IRQ0A */ + PINMUX_IRQ(evt2irq(0x0220), PORT20_FN0), /* IRQ1A */ + PINMUX_IRQ(evt2irq(0x0240), PORT11_FN0, PORT12_FN0), /* IRQ2A */ + PINMUX_IRQ(evt2irq(0x0260), PORT10_FN0, PORT14_FN0), /* IRQ3A */ + PINMUX_IRQ(evt2irq(0x0280), PORT15_FN0, PORT172_FN0), /* IRQ4A */ + PINMUX_IRQ(evt2irq(0x02A0), PORT0_FN0, PORT1_FN0), /* IRQ5A */ + PINMUX_IRQ(evt2irq(0x02C0), PORT121_FN0, PORT173_FN0), /* IRQ6A */ + PINMUX_IRQ(evt2irq(0x02E0), PORT120_FN0, PORT209_FN0), /* IRQ7A */ + PINMUX_IRQ(evt2irq(0x0300), PORT119_FN0), /* IRQ8A */ + PINMUX_IRQ(evt2irq(0x0320), PORT118_FN0, PORT210_FN0), /* IRQ9A */ + PINMUX_IRQ(evt2irq(0x0340), PORT19_FN0), /* IRQ10A */ + PINMUX_IRQ(evt2irq(0x0360), PORT104_FN0), /* IRQ11A */ + PINMUX_IRQ(evt2irq(0x0380), PORT42_FN0, PORT97_FN0), /* IRQ12A */ + PINMUX_IRQ(evt2irq(0x03A0), PORT64_FN0, PORT98_FN0), /* IRQ13A */ + PINMUX_IRQ(evt2irq(0x03C0), PORT63_FN0, PORT99_FN0), /* IRQ14A */ + PINMUX_IRQ(evt2irq(0x03E0), PORT62_FN0, PORT100_FN0), /* IRQ15A */ + PINMUX_IRQ(evt2irq(0x3200), PORT68_FN0, PORT211_FN0), /* IRQ16A */ + PINMUX_IRQ(evt2irq(0x3220), PORT69_FN0), /* IRQ17A */ + PINMUX_IRQ(evt2irq(0x3240), PORT70_FN0), /* IRQ18A */ + PINMUX_IRQ(evt2irq(0x3260), PORT71_FN0), /* IRQ19A */ + PINMUX_IRQ(evt2irq(0x3280), PORT67_FN0), /* IRQ20A */ + PINMUX_IRQ(evt2irq(0x32A0), PORT202_FN0), /* IRQ21A */ + PINMUX_IRQ(evt2irq(0x32C0), PORT95_FN0), /* IRQ22A */ + PINMUX_IRQ(evt2irq(0x32E0), PORT96_FN0), /* IRQ23A */ + PINMUX_IRQ(evt2irq(0x3300), PORT180_FN0), /* IRQ24A */ + PINMUX_IRQ(evt2irq(0x3320), PORT38_FN0), /* IRQ25A */ + PINMUX_IRQ(evt2irq(0x3340), PORT58_FN0, PORT81_FN0), /* IRQ26A */ + PINMUX_IRQ(evt2irq(0x3360), PORT57_FN0, PORT168_FN0), /* IRQ27A */ + PINMUX_IRQ(evt2irq(0x3380), PORT56_FN0, PORT169_FN0), /* IRQ28A */ + PINMUX_IRQ(evt2irq(0x33A0), PORT50_FN0, PORT170_FN0), /* IRQ29A */ + PINMUX_IRQ(evt2irq(0x33C0), PORT49_FN0, PORT171_FN0), /* IRQ30A */ + PINMUX_IRQ(evt2irq(0x33E0), PORT41_FN0, PORT167_FN0), /* IRQ31A */ +}; + static struct pinmux_info r8a7740_pinmux_info = { .name = "r8a7740_pfc", .reserved_id = PINMUX_RESERVED, @@ -2554,6 +2590,9 @@ static struct pinmux_info r8a7740_pinmux_info = { .gpio_data = pinmux_data, .gpio_data_size = ARRAY_SIZE(pinmux_data), + + .gpio_irq = pinmux_irqs, + .gpio_irq_size = ARRAY_SIZE(pinmux_irqs), }; void r8a7740_pinmux_init(void) diff --git a/arch/arm/mach-shmobile/pfc-sh73a0.c b/arch/arm/mach-shmobile/pfc-sh73a0.c index e05634ce2e0d..4a547b803268 100644 --- a/arch/arm/mach-shmobile/pfc-sh73a0.c +++ b/arch/arm/mach-shmobile/pfc-sh73a0.c @@ -829,14 +829,14 @@ static pinmux_enum_t pinmux_data[] = { PINMUX_DATA(PORT27_I2C_SCL2_MARK, PORT27_FN2, MSEL2CR_MSEL17_0, MSEL2CR_MSEL16_1), \ PINMUX_DATA(PORT27_I2C_SCL3_MARK, PORT27_FN3, MSEL2CR_MSEL19_0, - MSEL2CR_MSEL18_0), \ + MSEL2CR_MSEL18_1), \ PINMUX_DATA(MFG0_OUT1_MARK, PORT27_FN4), \ PINMUX_DATA(PORT27_IROUT_MARK, PORT27_FN7), PINMUX_DATA(XDVFS2_MARK, PORT28_FN1), \ PINMUX_DATA(PORT28_I2C_SDA2_MARK, PORT28_FN2, MSEL2CR_MSEL17_0, MSEL2CR_MSEL16_1), \ PINMUX_DATA(PORT28_I2C_SDA3_MARK, PORT28_FN3, MSEL2CR_MSEL19_0, - MSEL2CR_MSEL18_0), \ + MSEL2CR_MSEL18_1), \ PINMUX_DATA(PORT28_TPU1TO1_MARK, PORT28_FN7), PINMUX_DATA(SIM_RST_MARK, PORT29_FN1), \ PINMUX_DATA(PORT29_TPU1TO1_MARK, PORT29_FN4), diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c index 45fa3924c6a1..bacdd667e3b1 100644 --- a/arch/arm/mach-shmobile/platsmp.c +++ b/arch/arm/mach-shmobile/platsmp.c @@ -16,12 +16,16 @@ #include <linux/device.h> #include <linux/smp.h> #include <linux/io.h> +#include <linux/of.h> #include <asm/hardware/gic.h> #include <asm/mach-types.h> #include <mach/common.h> +#include <mach/emev2.h> -#define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2()) +#define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2() || \ + of_machine_is_compatible("renesas,sh73a0")) #define is_r8a7779() machine_is_marzen() +#define is_emev2() of_machine_is_compatible("renesas,emev2") static unsigned int __init shmobile_smp_get_core_count(void) { @@ -31,6 +35,9 @@ static unsigned int __init shmobile_smp_get_core_count(void) if (is_r8a7779()) return r8a7779_get_core_count(); + if (is_emev2()) + return emev2_get_core_count(); + return 1; } @@ -41,6 +48,9 @@ static void __init shmobile_smp_prepare_cpus(void) if (is_r8a7779()) r8a7779_smp_prepare_cpus(); + + if (is_emev2()) + emev2_smp_prepare_cpus(); } int shmobile_platform_cpu_kill(unsigned int cpu) @@ -48,6 +58,9 @@ int shmobile_platform_cpu_kill(unsigned int cpu) if (is_r8a7779()) return r8a7779_platform_cpu_kill(cpu); + if (is_emev2()) + return emev2_platform_cpu_kill(cpu); + return 1; } @@ -60,6 +73,9 @@ void __cpuinit platform_secondary_init(unsigned int cpu) if (is_r8a7779()) r8a7779_secondary_init(cpu); + + if (is_emev2()) + emev2_secondary_init(cpu); } int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) @@ -70,6 +86,9 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) if (is_r8a7779()) return r8a7779_boot_secondary(cpu); + if (is_emev2()) + return emev2_boot_secondary(cpu); + return -ENOSYS; } diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c new file mode 100644 index 000000000000..dae9aa68bb09 --- /dev/null +++ b/arch/arm/mach-shmobile/setup-emev2.c @@ -0,0 +1,452 @@ +/* + * Emma Mobile EV2 processor support + * + * Copyright (C) 2012 Magnus Damm + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * 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/kernel.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <linux/platform_data/gpio-em.h> +#include <linux/of_platform.h> +#include <linux/delay.h> +#include <linux/input.h> +#include <linux/io.h> +#include <linux/of_irq.h> +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/emev2.h> +#include <mach/irqs.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/time.h> +#include <asm/hardware/gic.h> + +static struct map_desc emev2_io_desc[] __initdata = { +#ifdef CONFIG_SMP + /* 128K entity map for 0xe0100000 (SMU) */ + { + .virtual = 0xe0100000, + .pfn = __phys_to_pfn(0xe0100000), + .length = SZ_128K, + .type = MT_DEVICE + }, + /* 2M mapping for SCU + L2 controller */ + { + .virtual = 0xf0000000, + .pfn = __phys_to_pfn(0x1e000000), + .length = SZ_2M, + .type = MT_DEVICE + }, +#endif +}; + +void __init emev2_map_io(void) +{ + iotable_init(emev2_io_desc, ARRAY_SIZE(emev2_io_desc)); +} + +/* UART */ +static struct resource uart0_resources[] = { + [0] = { + .start = 0xe1020000, + .end = 0xe1020037, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 40, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device uart0_device = { + .name = "serial8250-em", + .id = 0, + .num_resources = ARRAY_SIZE(uart0_resources), + .resource = uart0_resources, +}; + +static struct resource uart1_resources[] = { + [0] = { + .start = 0xe1030000, + .end = 0xe1030037, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 41, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device uart1_device = { + .name = "serial8250-em", + .id = 1, + .num_resources = ARRAY_SIZE(uart1_resources), + .resource = uart1_resources, +}; + +static struct resource uart2_resources[] = { + [0] = { + .start = 0xe1040000, + .end = 0xe1040037, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 42, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device uart2_device = { + .name = "serial8250-em", + .id = 2, + .num_resources = ARRAY_SIZE(uart2_resources), + .resource = uart2_resources, +}; + +static struct resource uart3_resources[] = { + [0] = { + .start = 0xe1050000, + .end = 0xe1050037, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 43, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device uart3_device = { + .name = "serial8250-em", + .id = 3, + .num_resources = ARRAY_SIZE(uart3_resources), + .resource = uart3_resources, +}; + +/* STI */ +static struct resource sti_resources[] = { + [0] = { + .name = "STI", + .start = 0xe0180000, + .end = 0xe0180053, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 157, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device sti_device = { + .name = "em_sti", + .id = 0, + .resource = sti_resources, + .num_resources = ARRAY_SIZE(sti_resources), +}; + + +/* GIO */ +static struct gpio_em_config gio0_config = { + .gpio_base = 0, + .irq_base = EMEV2_GPIO_IRQ(0), + .number_of_pins = 32, +}; + +static struct resource gio0_resources[] = { + [0] = { + .name = "GIO_000", + .start = 0xe0050000, + .end = 0xe005002b, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "GIO_000", + .start = 0xe0050040, + .end = 0xe005005f, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = 99, + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = 100, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device gio0_device = { + .name = "em_gio", + .id = 0, + .resource = gio0_resources, + .num_resources = ARRAY_SIZE(gio0_resources), + .dev = { + .platform_data = &gio0_config, + }, +}; + +static struct gpio_em_config gio1_config = { + .gpio_base = 32, + .irq_base = EMEV2_GPIO_IRQ(32), + .number_of_pins = 32, +}; + +static struct resource gio1_resources[] = { + [0] = { + .name = "GIO_032", + .start = 0xe0050080, + .end = 0xe00500ab, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "GIO_032", + .start = 0xe00500c0, + .end = 0xe00500df, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = 101, + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = 102, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device gio1_device = { + .name = "em_gio", + .id = 1, + .resource = gio1_resources, + .num_resources = ARRAY_SIZE(gio1_resources), + .dev = { + .platform_data = &gio1_config, + }, +}; + +static struct gpio_em_config gio2_config = { + .gpio_base = 64, + .irq_base = EMEV2_GPIO_IRQ(64), + .number_of_pins = 32, +}; + +static struct resource gio2_resources[] = { + [0] = { + .name = "GIO_064", + .start = 0xe0050100, + .end = 0xe005012b, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "GIO_064", + .start = 0xe0050140, + .end = 0xe005015f, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = 103, + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = 104, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device gio2_device = { + .name = "em_gio", + .id = 2, + .resource = gio2_resources, + .num_resources = ARRAY_SIZE(gio2_resources), + .dev = { + .platform_data = &gio2_config, + }, +}; + +static struct gpio_em_config gio3_config = { + .gpio_base = 96, + .irq_base = EMEV2_GPIO_IRQ(96), + .number_of_pins = 32, +}; + +static struct resource gio3_resources[] = { + [0] = { + .name = "GIO_096", + .start = 0xe0050100, + .end = 0xe005012b, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "GIO_096", + .start = 0xe0050140, + .end = 0xe005015f, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = 105, + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = 106, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device gio3_device = { + .name = "em_gio", + .id = 3, + .resource = gio3_resources, + .num_resources = ARRAY_SIZE(gio3_resources), + .dev = { + .platform_data = &gio3_config, + }, +}; + +static struct gpio_em_config gio4_config = { + .gpio_base = 128, + .irq_base = EMEV2_GPIO_IRQ(128), + .number_of_pins = 31, +}; + +static struct resource gio4_resources[] = { + [0] = { + .name = "GIO_128", + .start = 0xe0050200, + .end = 0xe005022b, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "GIO_128", + .start = 0xe0050240, + .end = 0xe005025f, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = 107, + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = 108, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device gio4_device = { + .name = "em_gio", + .id = 4, + .resource = gio4_resources, + .num_resources = ARRAY_SIZE(gio4_resources), + .dev = { + .platform_data = &gio4_config, + }, +}; + +static struct platform_device *emev2_early_devices[] __initdata = { + &uart0_device, + &uart1_device, + &uart2_device, + &uart3_device, +}; + +static struct platform_device *emev2_late_devices[] __initdata = { + &sti_device, + &gio0_device, + &gio1_device, + &gio2_device, + &gio3_device, + &gio4_device, +}; + +void __init emev2_add_standard_devices(void) +{ + emev2_clock_init(); + + platform_add_devices(emev2_early_devices, + ARRAY_SIZE(emev2_early_devices)); + + platform_add_devices(emev2_late_devices, + ARRAY_SIZE(emev2_late_devices)); +} + +void __init emev2_init_delay(void) +{ + shmobile_setup_delay(533, 1, 3); /* Cortex-A9 @ 533MHz */ +} + +void __init emev2_add_early_devices(void) +{ + emev2_init_delay(); + + early_platform_add_devices(emev2_early_devices, + ARRAY_SIZE(emev2_early_devices)); + + /* setup early console here as well */ + shmobile_setup_console(); +} + +void __init emev2_init_irq(void) +{ + void __iomem *gic_dist_base; + void __iomem *gic_cpu_base; + + /* Static mappings, never released */ + gic_dist_base = ioremap(0xe0028000, PAGE_SIZE); + gic_cpu_base = ioremap(0xe0020000, PAGE_SIZE); + BUG_ON(!gic_dist_base || !gic_cpu_base); + + /* Use GIC to handle interrupts */ + gic_init(0, 29, gic_dist_base, gic_cpu_base); +} + +#ifdef CONFIG_USE_OF +static const struct of_dev_auxdata emev2_auxdata_lookup[] __initconst = { + { } +}; + +void __init emev2_add_standard_devices_dt(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, + emev2_auxdata_lookup, NULL); +} + +static const struct of_device_id emev2_dt_irq_match[] = { + { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, + {}, +}; + +static const char *emev2_boards_compat_dt[] __initdata = { + "renesas,emev2", + NULL, +}; + +void __init emev2_init_irq_dt(void) +{ + of_irq_init(emev2_dt_irq_match); +} + +DT_MACHINE_START(EMEV2_DT, "Generic Emma Mobile EV2 (Flattened Device Tree)") + .init_early = emev2_init_delay, + .nr_irqs = NR_IRQS_LEGACY, + .init_irq = emev2_init_irq_dt, + .handle_irq = gic_handle_irq, + .init_machine = emev2_add_standard_devices_dt, + .timer = &shmobile_timer, + .dt_compat = emev2_boards_compat_dt, +MACHINE_END + +#endif /* CONFIG_USE_OF */ diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c index 14edb5cffa7f..ec4eb49c1693 100644 --- a/arch/arm/mach-shmobile/setup-r8a7740.c +++ b/arch/arm/mach-shmobile/setup-r8a7740.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/delay.h> +#include <linux/dma-mapping.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/io.h> @@ -60,6 +61,12 @@ static struct map_desc r8a7740_io_desc[] __initdata = { void __init r8a7740_map_io(void) { iotable_init(r8a7740_io_desc, ARRAY_SIZE(r8a7740_io_desc)); + + /* + * DMA memory at 0xff200000 - 0xffdfffff. The default 2MB size isn't + * enough to allocate the frame buffer memory. + */ + init_consistent_dma_size(12 << 20); } /* SCIFA0 */ @@ -350,19 +357,19 @@ static void r8a7740_i2c_workaround(struct platform_device *pdev) i2c_write(reg, ICSTART, i2c_read(reg, ICSTART) | 0x10); i2c_read(reg, ICSTART); /* dummy read */ - mdelay(100); + udelay(10); i2c_write(reg, ICCR, 0x01); - i2c_read(reg, ICCR); i2c_write(reg, ICSTART, 0x00); - i2c_read(reg, ICSTART); + + udelay(10); i2c_write(reg, ICCR, 0x10); - mdelay(100); + udelay(10); i2c_write(reg, ICCR, 0x00); - mdelay(100); + udelay(10); i2c_write(reg, ICCR, 0x10); - mdelay(100); + udelay(10); iounmap(reg); } diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index 2fe8f83ca124..6a4bd582c028 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c @@ -22,6 +22,7 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/platform_device.h> +#include <linux/of_platform.h> #include <linux/uio_driver.h> #include <linux/delay.h> #include <linux/input.h> @@ -461,6 +462,16 @@ static const struct sh_dmae_slave_config sh7372_dmae_slaves[] = { .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT), .mid_rid = 0xce, }, { + .slave_id = SHDMA_SLAVE_FSIA_TX, + .addr = 0xfe1f0024, + .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT), + .mid_rid = 0xb1, + }, { + .slave_id = SHDMA_SLAVE_FSIA_RX, + .addr = 0xfe1f0020, + .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT), + .mid_rid = 0xb2, + }, { .slave_id = SHDMA_SLAVE_MMCIF_TX, .addr = 0xe6bd0034, .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT), @@ -1092,3 +1103,50 @@ void __init sh7372_add_early_devices(void) /* override timer setup with soc-specific code */ shmobile_timer.init = sh7372_earlytimer_init; } + +#ifdef CONFIG_USE_OF + +void __init sh7372_add_early_devices_dt(void) +{ + shmobile_setup_delay(800, 1, 3); /* Cortex-A8 @ 800MHz */ + + early_platform_add_devices(sh7372_early_devices, + ARRAY_SIZE(sh7372_early_devices)); + + /* setup early console here as well */ + shmobile_setup_console(); +} + +static const struct of_dev_auxdata sh7372_auxdata_lookup[] __initconst = { + { } +}; + +void __init sh7372_add_standard_devices_dt(void) +{ + /* clocks are setup late during boot in the case of DT */ + sh7372_clock_init(); + + platform_add_devices(sh7372_early_devices, + ARRAY_SIZE(sh7372_early_devices)); + + of_platform_populate(NULL, of_default_bus_match_table, + sh7372_auxdata_lookup, NULL); +} + +static const char *sh7372_boards_compat_dt[] __initdata = { + "renesas,sh7372", + NULL, +}; + +DT_MACHINE_START(SH7372_DT, "Generic SH7372 (Flattened Device Tree)") + .map_io = sh7372_map_io, + .init_early = sh7372_add_early_devices_dt, + .nr_irqs = NR_IRQS_LEGACY, + .init_irq = sh7372_init_irq, + .handle_irq = shmobile_handle_irq_intc, + .init_machine = sh7372_add_standard_devices_dt, + .timer = &shmobile_timer, + .dt_compat = sh7372_boards_compat_dt, +MACHINE_END + +#endif /* CONFIG_USE_OF */ diff --git a/arch/arm/mach-shmobile/smp-emev2.c b/arch/arm/mach-shmobile/smp-emev2.c new file mode 100644 index 000000000000..6a35c4a31e6c --- /dev/null +++ b/arch/arm/mach-shmobile/smp-emev2.c @@ -0,0 +1,97 @@ +/* + * SMP support for Emma Mobile EV2 + * + * Copyright (C) 2012 Renesas Solutions Corp. + * Copyright (C) 2012 Magnus Damm + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * 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/kernel.h> +#include <linux/init.h> +#include <linux/smp.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <mach/common.h> +#include <mach/emev2.h> +#include <asm/smp_plat.h> +#include <asm/smp_scu.h> +#include <asm/hardware/gic.h> +#include <asm/cacheflush.h> + +#define EMEV2_SCU_BASE 0x1e000000 + +static DEFINE_SPINLOCK(scu_lock); +static void __iomem *scu_base; + +static void modify_scu_cpu_psr(unsigned long set, unsigned long clr) +{ + unsigned long tmp; + + /* we assume this code is running on a different cpu + * than the one that is changing coherency setting */ + spin_lock(&scu_lock); + tmp = readl(scu_base + 8); + tmp &= ~clr; + tmp |= set; + writel(tmp, scu_base + 8); + spin_unlock(&scu_lock); + +} + +unsigned int __init emev2_get_core_count(void) +{ + if (!scu_base) { + scu_base = ioremap(EMEV2_SCU_BASE, PAGE_SIZE); + emev2_clock_init(); /* need ioremapped SMU */ + } + + WARN_ON_ONCE(!scu_base); + + return scu_base ? scu_get_core_count(scu_base) : 1; +} + +int emev2_platform_cpu_kill(unsigned int cpu) +{ + return 0; /* not supported yet */ +} + +void __cpuinit emev2_secondary_init(unsigned int cpu) +{ + gic_secondary_init(0); +} + +int __cpuinit emev2_boot_secondary(unsigned int cpu) +{ + cpu = cpu_logical_map(cpu); + + /* enable cache coherency */ + modify_scu_cpu_psr(0, 3 << (cpu * 8)); + + /* Tell ROM loader about our vector (in headsmp.S) */ + emev2_set_boot_vector(__pa(shmobile_secondary_vector)); + + gic_raise_softirq(cpumask_of(cpu), 1); + return 0; +} + +void __init emev2_smp_prepare_cpus(void) +{ + int cpu = cpu_logical_map(0); + + scu_enable(scu_base); + + /* enable cache coherency on CPU0 */ + modify_scu_cpu_psr(0, 3 << (cpu * 8)); +} diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c index 8b79e7917a23..a68919727e24 100644 --- a/arch/arm/mach-shmobile/timer.c +++ b/arch/arm/mach-shmobile/timer.c @@ -19,9 +19,27 @@ * */ #include <linux/platform_device.h> +#include <linux/delay.h> #include <asm/mach/time.h> #include <asm/smp_twd.h> +void __init shmobile_setup_delay(unsigned int max_cpu_core_mhz, + unsigned int mult, unsigned int div) +{ + /* calculate a worst-case loops-per-jiffy value + * based on maximum cpu core mhz setting and the + * __delay() implementation in arch/arm/lib/delay.S + * + * this will result in a longer delay than expected + * when the cpu core runs on lower frequencies. + */ + + unsigned int value = (1000000 * mult) / (HZ * div); + + if (!preset_lpj) + preset_lpj = max_cpu_core_mhz * value; +} + static void __init shmobile_late_time_init(void) { /* |