From af75655c066621352c419646ec0775e9523dc720 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Mon, 25 Jul 2011 17:36:42 +0100 Subject: picoxcell: support for Picochip picoxcell devices picoXcell is a family of femtocell devices with an ARM application processor and picoArray DSP processor array. This patch adds support for picoXcell boards to be booted using the device tree registering the VIC's, UART's and timers. v3: - fixup vic compatible string in binding v2: - cleanup empty mach headers - convert to of_platform_populate() - simplify uncompress.h - split vic node into 2 devices - add missing __initconst attributes Signed-off-by: Jamie Iles --- arch/arm/Kconfig | 18 +++ arch/arm/Makefile | 1 + arch/arm/mach-picoxcell/Makefile | 3 + arch/arm/mach-picoxcell/Makefile.boot | 1 + arch/arm/mach-picoxcell/common.c | 55 +++++++++ arch/arm/mach-picoxcell/common.h | 18 +++ arch/arm/mach-picoxcell/include/mach/debug-macro.S | 35 ++++++ arch/arm/mach-picoxcell/include/mach/entry-macro.S | 19 +++ arch/arm/mach-picoxcell/include/mach/gpio.h | 1 + arch/arm/mach-picoxcell/include/mach/hardware.h | 21 ++++ arch/arm/mach-picoxcell/include/mach/io.h | 29 +++++ arch/arm/mach-picoxcell/include/mach/irqs.h | 25 ++++ arch/arm/mach-picoxcell/include/mach/map.h | 25 ++++ arch/arm/mach-picoxcell/include/mach/memory.h | 1 + .../mach-picoxcell/include/mach/picoxcell_soc.h | 25 ++++ arch/arm/mach-picoxcell/include/mach/system.h | 31 +++++ arch/arm/mach-picoxcell/include/mach/timex.h | 25 ++++ arch/arm/mach-picoxcell/include/mach/uncompress.h | 21 ++++ arch/arm/mach-picoxcell/include/mach/vmalloc.h | 18 +++ arch/arm/mach-picoxcell/io.c | 56 +++++++++ arch/arm/mach-picoxcell/time.c | 132 +++++++++++++++++++++ 21 files changed, 560 insertions(+) create mode 100644 arch/arm/mach-picoxcell/Makefile create mode 100644 arch/arm/mach-picoxcell/Makefile.boot create mode 100644 arch/arm/mach-picoxcell/common.c create mode 100644 arch/arm/mach-picoxcell/common.h create mode 100644 arch/arm/mach-picoxcell/include/mach/debug-macro.S create mode 100644 arch/arm/mach-picoxcell/include/mach/entry-macro.S create mode 100644 arch/arm/mach-picoxcell/include/mach/gpio.h create mode 100644 arch/arm/mach-picoxcell/include/mach/hardware.h create mode 100644 arch/arm/mach-picoxcell/include/mach/io.h create mode 100644 arch/arm/mach-picoxcell/include/mach/irqs.h create mode 100644 arch/arm/mach-picoxcell/include/mach/map.h create mode 100644 arch/arm/mach-picoxcell/include/mach/memory.h create mode 100644 arch/arm/mach-picoxcell/include/mach/picoxcell_soc.h create mode 100644 arch/arm/mach-picoxcell/include/mach/system.h create mode 100644 arch/arm/mach-picoxcell/include/mach/timex.h create mode 100644 arch/arm/mach-picoxcell/include/mach/uncompress.h create mode 100644 arch/arm/mach-picoxcell/include/mach/vmalloc.h create mode 100644 arch/arm/mach-picoxcell/io.c create mode 100644 arch/arm/mach-picoxcell/time.c (limited to 'arch') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 5ebc5d922ea1..15fab78eee29 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -608,6 +608,24 @@ config ARCH_TEGRA This enables support for NVIDIA Tegra based systems (Tegra APX, Tegra 6xx and Tegra 2 series). +config ARCH_PICOXCELL + bool "Picochip picoXcell" + select ARCH_REQUIRE_GPIOLIB + select ARM_PATCH_PHYS_VIRT + select ARM_VIC + select CPU_V6K + select DW_APB_TIMER + select GENERIC_CLOCKEVENTS + select GENERIC_GPIO + select HAVE_SCHED_CLOCK + select HAVE_TCM + select NO_IOPORT + select USE_OF + help + This enables support for systems based on the Picochip picoXcell + family of Femtocell devices. The picoxcell support requires device tree + for all boards. + config ARCH_PNX4008 bool "Philips Nexperia PNX4008 Mobile" select CPU_ARM926T diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 70c424eaf7b0..c94139963f79 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -167,6 +167,7 @@ machine-$(CONFIG_ARCH_OMAP2) := omap2 machine-$(CONFIG_ARCH_OMAP3) := omap2 machine-$(CONFIG_ARCH_OMAP4) := omap2 machine-$(CONFIG_ARCH_ORION5X) := orion5x +machine-$(CONFIG_ARCH_PICOXCELL) := picoxcell machine-$(CONFIG_ARCH_PNX4008) := pnx4008 machine-$(CONFIG_ARCH_PRIMA2) := prima2 machine-$(CONFIG_ARCH_PXA) := pxa diff --git a/arch/arm/mach-picoxcell/Makefile b/arch/arm/mach-picoxcell/Makefile new file mode 100644 index 000000000000..c550b6363488 --- /dev/null +++ b/arch/arm/mach-picoxcell/Makefile @@ -0,0 +1,3 @@ +obj-y := common.o +obj-y += time.o +obj-y += io.o diff --git a/arch/arm/mach-picoxcell/Makefile.boot b/arch/arm/mach-picoxcell/Makefile.boot new file mode 100644 index 000000000000..b3271754e9fd --- /dev/null +++ b/arch/arm/mach-picoxcell/Makefile.boot @@ -0,0 +1 @@ +zreladdr-y := 0x00008000 diff --git a/arch/arm/mach-picoxcell/common.c b/arch/arm/mach-picoxcell/common.c new file mode 100644 index 000000000000..34d08347be5f --- /dev/null +++ b/arch/arm/mach-picoxcell/common.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011 Picochip Ltd., Jamie Iles + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * All enquiries to support@picochip.com + */ +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "common.h" + +static void __init picoxcell_init_machine(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); +} + +static const char *picoxcell_dt_match[] = { + "picochip,pc3x2", + "picochip,pc3x3", + NULL +}; + +static const struct of_device_id vic_of_match[] __initconst = { + { .compatible = "arm,pl192-vic" }, + { /* Sentinel */ } +}; + +static void __init picoxcell_init_irq(void) +{ + vic_init(IO_ADDRESS(PICOXCELL_VIC0_BASE), 0, ~0, 0); + vic_init(IO_ADDRESS(PICOXCELL_VIC1_BASE), 32, ~0, 0); + irq_domain_generate_simple(vic_of_match, PICOXCELL_VIC0_BASE, 0); + irq_domain_generate_simple(vic_of_match, PICOXCELL_VIC1_BASE, 32); +} + +DT_MACHINE_START(PICOXCELL, "Picochip picoXcell") + .map_io = picoxcell_map_io, + .nr_irqs = ARCH_NR_IRQS, + .init_irq = picoxcell_init_irq, + .timer = &picoxcell_timer, + .init_machine = picoxcell_init_machine, + .dt_compat = picoxcell_dt_match, +MACHINE_END diff --git a/arch/arm/mach-picoxcell/common.h b/arch/arm/mach-picoxcell/common.h new file mode 100644 index 000000000000..5263f0fa095c --- /dev/null +++ b/arch/arm/mach-picoxcell/common.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2011 Picochip Ltd., Jamie Iles + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * All enquiries to support@picochip.com + */ +#ifndef __PICOXCELL_COMMON_H__ +#define __PICOXCELL_COMMON_H__ + +#include + +extern struct sys_timer picoxcell_timer; +extern void picoxcell_map_io(void); + +#endif /* __PICOXCELL_COMMON_H__ */ diff --git a/arch/arm/mach-picoxcell/include/mach/debug-macro.S b/arch/arm/mach-picoxcell/include/mach/debug-macro.S new file mode 100644 index 000000000000..8f2c234ed9d9 --- /dev/null +++ b/arch/arm/mach-picoxcell/include/mach/debug-macro.S @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 Picochip Ltd., Jamie Iles + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Derived from arch/arm/mach-davinci/include/mach/debug-macro.S to use 32-bit + * accesses to the 8250. + */ +#include +#include +#include + +#define UART_SHIFT 2 + + .macro addruart, rp, rv + ldr \rv, =PHYS_TO_IO(PICOXCELL_UART1_BASE) + ldr \rp, =PICOXCELL_UART1_BASE + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #UART_TX << UART_SHIFT] + .endm + + .macro busyuart,rd,rx +1002: ldr \rd, [\rx, #UART_LSR << UART_SHIFT] + and \rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE + teq \rd, #UART_LSR_TEMT | UART_LSR_THRE + bne 1002b + .endm + + /* The UART's don't have any flow control IO's wired up. */ + .macro waituart,rd,rx + .endm diff --git a/arch/arm/mach-picoxcell/include/mach/entry-macro.S b/arch/arm/mach-picoxcell/include/mach/entry-macro.S new file mode 100644 index 000000000000..a6b09f75d9df --- /dev/null +++ b/arch/arm/mach-picoxcell/include/mach/entry-macro.S @@ -0,0 +1,19 @@ +/* + * entry-macro.S + * + * Copyright (c) 2011 Picochip Ltd., Jamie Iles + * + * Low-level IRQ helper macros for picoXcell platforms + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ +#include +#include +#include + +#define VA_VIC0 IO_ADDRESS(PICOXCELL_VIC0_BASE) +#define VA_VIC1 IO_ADDRESS(PICOXCELL_VIC1_BASE) + +#include diff --git a/arch/arm/mach-picoxcell/include/mach/gpio.h b/arch/arm/mach-picoxcell/include/mach/gpio.h new file mode 100644 index 000000000000..40a8c178f10d --- /dev/null +++ b/arch/arm/mach-picoxcell/include/mach/gpio.h @@ -0,0 +1 @@ +/* empty */ diff --git a/arch/arm/mach-picoxcell/include/mach/hardware.h b/arch/arm/mach-picoxcell/include/mach/hardware.h new file mode 100644 index 000000000000..70ff58192ec9 --- /dev/null +++ b/arch/arm/mach-picoxcell/include/mach/hardware.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2011 Picochip Ltd., Jamie Iles + * + * This file contains the hardware definitions of the picoXcell SoC devices. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include + +#endif diff --git a/arch/arm/mach-picoxcell/include/mach/io.h b/arch/arm/mach-picoxcell/include/mach/io.h new file mode 100644 index 000000000000..a863b0f6eeec --- /dev/null +++ b/arch/arm/mach-picoxcell/include/mach/io.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 Picochip Ltd., Jamie Iles + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +/* No ioports, but needed for driver compatibility. */ +#define __io(a) __typesafe_io(a) +/* No PCI possible on picoxcell. */ +#define __mem_pci(a) (a) + +#define __arch_ioremap picoxcell_ioremap +#define __arch_iounmap picoxcell_iounmap + +extern void __iomem *picoxcell_ioremap(unsigned long phys, size_t size, + unsigned int type); +extern void picoxcell_iounmap(volatile void __iomem *addr); + +#endif /* __ASM_ARM_ARCH_IO_H */ diff --git a/arch/arm/mach-picoxcell/include/mach/irqs.h b/arch/arm/mach-picoxcell/include/mach/irqs.h new file mode 100644 index 000000000000..4d13ed970919 --- /dev/null +++ b/arch/arm/mach-picoxcell/include/mach/irqs.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Picochip Ltd., Jamie Iles + * + * This file contains the hardware definitions of the picoXcell SoC devices. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ +#ifndef __MACH_IRQS_H +#define __MACH_IRQS_H + +#define ARCH_NR_IRQS 64 +#define NR_IRQS (128 + ARCH_NR_IRQS) + +#define IRQ_VIC0_BASE 0 +#define IRQ_VIC1_BASE 32 + +#endif /* __MACH_IRQS_H */ diff --git a/arch/arm/mach-picoxcell/include/mach/map.h b/arch/arm/mach-picoxcell/include/mach/map.h new file mode 100644 index 000000000000..c06afad218bb --- /dev/null +++ b/arch/arm/mach-picoxcell/include/mach/map.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Picochip Ltd., Jamie Iles + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ +#ifndef __PICOXCELL_MAP_H__ +#define __PICOXCELL_MAP_H__ + +#define PHYS_TO_IO(x) (((x) & 0x00ffffff) | 0xfe000000) + +#ifdef __ASSEMBLY__ +#define IO_ADDRESS(x) PHYS_TO_IO((x)) +#else +#define IO_ADDRESS(x) (void __iomem __force *)(PHYS_TO_IO((x))) +#endif + +#endif /* __PICOXCELL_MAP_H__ */ diff --git a/arch/arm/mach-picoxcell/include/mach/memory.h b/arch/arm/mach-picoxcell/include/mach/memory.h new file mode 100644 index 000000000000..40a8c178f10d --- /dev/null +++ b/arch/arm/mach-picoxcell/include/mach/memory.h @@ -0,0 +1 @@ +/* empty */ diff --git a/arch/arm/mach-picoxcell/include/mach/picoxcell_soc.h b/arch/arm/mach-picoxcell/include/mach/picoxcell_soc.h new file mode 100644 index 000000000000..5566fc88ddbc --- /dev/null +++ b/arch/arm/mach-picoxcell/include/mach/picoxcell_soc.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Picochip Ltd., Jamie Iles + * + * This file contains the hardware definitions of the picoXcell SoC devices. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ +#ifndef __PICOXCELL_SOC_H__ +#define __PICOXCELL_SOC_H__ + +#define PICOXCELL_UART1_BASE 0x80230000 +#define PICOXCELL_PERIPH_BASE 0x80000000 +#define PICOXCELL_PERIPH_LENGTH SZ_4M +#define PICOXCELL_VIC0_BASE 0x80060000 +#define PICOXCELL_VIC1_BASE 0x80064000 + +#endif /* __PICOXCELL_SOC_H__ */ diff --git a/arch/arm/mach-picoxcell/include/mach/system.h b/arch/arm/mach-picoxcell/include/mach/system.h new file mode 100644 index 000000000000..67c589b0c1bc --- /dev/null +++ b/arch/arm/mach-picoxcell/include/mach/system.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Picochip Ltd., Jamie Iles + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +static inline void arch_idle(void) +{ + /* + * This should do all the clock switching and wait for interrupt + * tricks. + */ + cpu_do_idle(); +} + +static inline void arch_reset(int mode, const char *cmd) +{ + /* Watchdog reset to go here. */ +} + +#endif /* __ASM_ARCH_SYSTEM_H */ diff --git a/arch/arm/mach-picoxcell/include/mach/timex.h b/arch/arm/mach-picoxcell/include/mach/timex.h new file mode 100644 index 000000000000..6c540a69f405 --- /dev/null +++ b/arch/arm/mach-picoxcell/include/mach/timex.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Picochip Ltd., Jamie Iles + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __TIMEX_H__ +#define __TIMEX_H__ + +/* Bogus value to allow the kernel to compile. */ +#define CLOCK_TICK_RATE 1000000 + +#endif /* __TIMEX_H__ */ + diff --git a/arch/arm/mach-picoxcell/include/mach/uncompress.h b/arch/arm/mach-picoxcell/include/mach/uncompress.h new file mode 100644 index 000000000000..b60b19d1d739 --- /dev/null +++ b/arch/arm/mach-picoxcell/include/mach/uncompress.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2011 Picochip Ltd., Jamie Iles + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define putc(c) +#define flush() +#define arch_decomp_setup() +#define arch_decomp_wdog() diff --git a/arch/arm/mach-picoxcell/include/mach/vmalloc.h b/arch/arm/mach-picoxcell/include/mach/vmalloc.h new file mode 100644 index 000000000000..62559e30888a --- /dev/null +++ b/arch/arm/mach-picoxcell/include/mach/vmalloc.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2011 Picochip Ltd., Jamie Iles + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define VMALLOC_END 0xFE000000UL diff --git a/arch/arm/mach-picoxcell/io.c b/arch/arm/mach-picoxcell/io.c new file mode 100644 index 000000000000..935a2fae62e6 --- /dev/null +++ b/arch/arm/mach-picoxcell/io.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011 Picochip Ltd., Jamie Iles + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * All enquiries to support@picochip.com + */ +#include +#include +#include +#include + +#include + +#include +#include + +#include "common.h" + +void __init picoxcell_map_io(void) +{ + struct map_desc io_map = { + .virtual = PHYS_TO_IO(PICOXCELL_PERIPH_BASE), + .pfn = __phys_to_pfn(PICOXCELL_PERIPH_BASE), + .length = PICOXCELL_PERIPH_LENGTH, + .type = MT_DEVICE, + }; + + iotable_init(&io_map, 1); +} + +void __iomem *picoxcell_ioremap(unsigned long p, size_t size, + unsigned int type) +{ + if (unlikely(size == 0)) + return NULL; + + if (p >= PICOXCELL_PERIPH_BASE && + p < PICOXCELL_PERIPH_BASE + PICOXCELL_PERIPH_LENGTH) + return IO_ADDRESS(p); + + return __arm_ioremap_caller(p, size, type, + __builtin_return_address(0)); +} +EXPORT_SYMBOL_GPL(picoxcell_ioremap); + +void picoxcell_iounmap(volatile void __iomem *addr) +{ + unsigned long virt = (unsigned long)addr; + + if (virt >= VMALLOC_START && virt < VMALLOC_END) + __iounmap(addr); +} +EXPORT_SYMBOL_GPL(picoxcell_iounmap); diff --git a/arch/arm/mach-picoxcell/time.c b/arch/arm/mach-picoxcell/time.c new file mode 100644 index 000000000000..90a554ff4499 --- /dev/null +++ b/arch/arm/mach-picoxcell/time.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2011 Picochip Ltd., Jamie Iles + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * All enquiries to support@picochip.com + */ +#include +#include +#include +#include +#include + +#include +#include + +#include "common.h" + +static void timer_get_base_and_rate(struct device_node *np, + void __iomem **base, u32 *rate) +{ + *base = of_iomap(np, 0); + + if (!*base) + panic("Unable to map regs for %s", np->name); + + if (of_property_read_u32(np, "clock-freq", rate)) + panic("No clock-freq property for %s", np->name); +} + +static void picoxcell_add_clockevent(struct device_node *event_timer) +{ + void __iomem *iobase; + struct dw_apb_clock_event_device *ced; + u32 irq, rate; + + irq = irq_of_parse_and_map(event_timer, 0); + if (irq == NO_IRQ) + panic("No IRQ for clock event timer"); + + timer_get_base_and_rate(event_timer, &iobase, &rate); + + ced = dw_apb_clockevent_init(0, event_timer->name, 300, iobase, irq, + rate); + if (!ced) + panic("Unable to initialise clockevent device"); + + dw_apb_clockevent_register(ced); +} + +static void picoxcell_add_clocksource(struct device_node *source_timer) +{ + void __iomem *iobase; + struct dw_apb_clocksource *cs; + u32 rate; + + timer_get_base_and_rate(source_timer, &iobase, &rate); + + cs = dw_apb_clocksource_init(300, source_timer->name, iobase, rate); + if (!cs) + panic("Unable to initialise clocksource device"); + + dw_apb_clocksource_start(cs); + dw_apb_clocksource_register(cs); +} + +static DEFINE_CLOCK_DATA(cd); +static void __iomem *sched_io_base; + +unsigned long long notrace sched_clock(void) +{ + cycle_t cyc = sched_io_base ? __raw_readl(sched_io_base) : 0; + + return cyc_to_sched_clock(&cd, cyc, (u32)~0); +} + +static void notrace picoxcell_update_sched_clock(void) +{ + cycle_t cyc = sched_io_base ? __raw_readl(sched_io_base) : 0; + + update_sched_clock(&cd, cyc, (u32)~0); +} + +static const struct of_device_id picoxcell_rtc_ids[] __initconst = { + { .compatible = "picochip,pc3x2-rtc" }, + { /* Sentinel */ }, +}; + +static void picoxcell_init_sched_clock(void) +{ + struct device_node *sched_timer; + u32 rate; + + sched_timer = of_find_matching_node(NULL, picoxcell_rtc_ids); + if (!sched_timer) + panic("No RTC for sched clock to use"); + + timer_get_base_and_rate(sched_timer, &sched_io_base, &rate); + of_node_put(sched_timer); + + init_sched_clock(&cd, picoxcell_update_sched_clock, 32, rate); +} + +static const struct of_device_id picoxcell_timer_ids[] __initconst = { + { .compatible = "picochip,pc3x2-timer" }, + {}, +}; + +static void __init picoxcell_timer_init(void) +{ + struct device_node *event_timer, *source_timer; + + event_timer = of_find_matching_node(NULL, picoxcell_timer_ids); + if (!event_timer) + panic("No timer for clockevent"); + picoxcell_add_clockevent(event_timer); + + source_timer = of_find_matching_node(event_timer, picoxcell_timer_ids); + if (!source_timer) + panic("No timer for clocksource"); + picoxcell_add_clocksource(source_timer); + + of_node_put(source_timer); + + picoxcell_init_sched_clock(); +} + +struct sys_timer picoxcell_timer = { + .init = picoxcell_timer_init, +}; -- cgit v1.2.3 From fee7565679e39039bdd8083e9f1a54151ffac6d9 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Mon, 1 Aug 2011 14:23:36 +0100 Subject: picoxcell: add the DTS for pc3x2 and pc3x3 devices This describes the basic hierarchy of picoxcell pc3x3 devices including clocks and bus interconnect. Some onchip devices are currently omitted as there haven't been bindings created for them. v2: - change timer compatible strings to be more soc specific - split vic node into 2 devices Signed-off-by: Jamie Iles --- arch/arm/boot/dts/picoxcell-pc3x2.dtsi | 249 ++++++++++++++++++++++ arch/arm/boot/dts/picoxcell-pc3x3.dtsi | 365 +++++++++++++++++++++++++++++++++ 2 files changed, 614 insertions(+) create mode 100644 arch/arm/boot/dts/picoxcell-pc3x2.dtsi create mode 100644 arch/arm/boot/dts/picoxcell-pc3x3.dtsi (limited to 'arch') diff --git a/arch/arm/boot/dts/picoxcell-pc3x2.dtsi b/arch/arm/boot/dts/picoxcell-pc3x2.dtsi new file mode 100644 index 000000000000..f0a8c2068ea7 --- /dev/null +++ b/arch/arm/boot/dts/picoxcell-pc3x2.dtsi @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2011 Picochip, Jamie Iles + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ +/include/ "skeleton.dtsi" +/ { + model = "Picochip picoXcell PC3X2"; + compatible = "picochip,pc3x2"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,1176jz-s"; + clock-frequency = <400000000>; + reg = <0>; + d-cache-line-size = <32>; + d-cache-size = <32768>; + i-cache-line-size = <32>; + i-cache-size = <32768>; + }; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + pclk: clock@0 { + compatible = "fixed-clock"; + clock-outputs = "bus", "pclk"; + clock-frequency = <200000000>; + ref-clock = <&ref_clk>, "ref"; + }; + }; + + paxi { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x80000000 0x400000>; + + emac: gem@30000 { + compatible = "cadence,gem"; + reg = <0x30000 0x10000>; + interrupts = <31>; + }; + + dmac1: dmac@40000 { + compatible = "snps,dw-dmac"; + reg = <0x40000 0x10000>; + interrupts = <25>; + }; + + dmac2: dmac@50000 { + compatible = "snps,dw-dmac"; + reg = <0x50000 0x10000>; + interrupts = <26>; + }; + + vic0: interrupt-controller@60000 { + compatible = "arm,pl192-vic"; + interrupt-controller; + reg = <0x60000 0x1000>; + #interrupt-cells = <1>; + }; + + vic1: interrupt-controller@64000 { + compatible = "arm,pl192-vic"; + interrupt-controller; + reg = <0x64000 0x1000>; + #interrupt-cells = <1>; + }; + + fuse: picoxcell-fuse@80000 { + compatible = "picoxcell,fuse-pc3x2"; + reg = <0x80000 0x10000>; + }; + + ssi: picoxcell-spi@90000 { + compatible = "picoxcell,spi"; + reg = <0x90000 0x10000>; + interrupt-parent = <&vic0>; + interrupts = <10>; + }; + + ipsec: spacc@100000 { + compatible = "picochip,spacc-ipsec"; + reg = <0x100000 0x10000>; + interrupt-parent = <&vic0>; + interrupts = <24>; + ref-clock = <&pclk>, "ref"; + }; + + srtp: spacc@140000 { + compatible = "picochip,spacc-srtp"; + reg = <0x140000 0x10000>; + interrupt-parent = <&vic0>; + interrupts = <23>; + }; + + l2_engine: spacc@180000 { + compatible = "picochip,spacc-l2"; + reg = <0x180000 0x10000>; + interrupt-parent = <&vic0>; + interrupts = <22>; + ref-clock = <&pclk>, "ref"; + }; + + apb { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x200000 0x80000>; + + rtc0: rtc@00000 { + compatible = "picochip,pc3x2-rtc"; + clock-freq = <200000000>; + reg = <0x00000 0xf>; + interrupt-parent = <&vic1>; + interrupts = <8>; + }; + + timer0: timer@10000 { + compatible = "picochip,pc3x2-timer"; + interrupt-parent = <&vic0>; + interrupts = <4>; + clock-freq = <200000000>; + reg = <0x10000 0x14>; + }; + + timer1: timer@10014 { + compatible = "picochip,pc3x2-timer"; + interrupt-parent = <&vic0>; + interrupts = <5>; + clock-freq = <200000000>; + reg = <0x10014 0x14>; + }; + + timer2: timer@10028 { + compatible = "picochip,pc3x2-timer"; + interrupt-parent = <&vic0>; + interrupts = <6>; + clock-freq = <200000000>; + reg = <0x10028 0x14>; + }; + + timer3: timer@1003c { + compatible = "picochip,pc3x2-timer"; + interrupt-parent = <&vic0>; + interrupts = <7>; + clock-freq = <200000000>; + reg = <0x1003c 0x14>; + }; + + gpio: gpio@20000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x20000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + reg-io-width = <4>; + + banka: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + gpio-generic,nr-gpio = <8>; + + regoffset-dat = <0x50>; + regoffset-set = <0x00>; + regoffset-dirout = <0x04>; + }; + + bankb: gpio-controller@1 { + compatible = "snps,dw-apb-gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + gpio-generic,nr-gpio = <8>; + + regoffset-dat = <0x54>; + regoffset-set = <0x0c>; + regoffset-dirout = <0x10>; + }; + }; + + uart0: uart@30000 { + compatible = "snps,dw-apb-uart"; + reg = <0x30000 0x1000>; + interrupt-parent = <&vic1>; + interrupts = <10>; + clock-frequency = <3686400>; + reg-shift = <2>; + reg-io-width = <4>; + }; + + uart1: uart@40000 { + compatible = "snps,dw-apb-uart"; + reg = <0x40000 0x1000>; + interrupt-parent = <&vic1>; + interrupts = <9>; + clock-frequency = <3686400>; + reg-shift = <2>; + reg-io-width = <4>; + }; + + wdog: watchdog@50000 { + compatible = "snps,dw-apb-wdg"; + reg = <0x50000 0x10000>; + interrupt-parent = <&vic0>; + interrupts = <11>; + bus-clock = <&pclk>, "bus"; + }; + }; + }; + + rwid-axi { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges; + + ebi@50000000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0x40000000 0x08000000 + 1 0 0x48000000 0x08000000 + 2 0 0x50000000 0x08000000 + 3 0 0x58000000 0x08000000>; + }; + + axi2pico@c0000000 { + compatible = "picochip,axi2pico-pc3x2"; + reg = <0xc0000000 0x10000>; + interrupts = <13 14 15 16 17 18 19 20 21>; + }; + }; +}; diff --git a/arch/arm/boot/dts/picoxcell-pc3x3.dtsi b/arch/arm/boot/dts/picoxcell-pc3x3.dtsi new file mode 100644 index 000000000000..daa962d191e6 --- /dev/null +++ b/arch/arm/boot/dts/picoxcell-pc3x3.dtsi @@ -0,0 +1,365 @@ +/* + * Copyright (C) 2011 Picochip, Jamie Iles + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ +/include/ "skeleton.dtsi" +/ { + model = "Picochip picoXcell PC3X3"; + compatible = "picochip,pc3x3"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,1176jz-s"; + cpu-clock = <&arm_clk>, "cpu"; + reg = <0>; + d-cache-line-size = <32>; + d-cache-size = <32768>; + i-cache-line-size = <32>; + i-cache-size = <32768>; + }; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + clkgate: clkgate@800a0048 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x800a0048 4>; + compatible = "picochip,pc3x3-clk-gate"; + + tzprot_clk: clock@0 { + compatible = "picochip,pc3x3-gated-clk"; + clock-outputs = "bus"; + picochip,clk-disable-bit = <0>; + clock-frequency = <200000000>; + ref-clock = <&ref_clk>, "ref"; + }; + + spi_clk: clock@1 { + compatible = "picochip,pc3x3-gated-clk"; + clock-outputs = "bus"; + picochip,clk-disable-bit = <1>; + clock-frequency = <200000000>; + ref-clock = <&ref_clk>, "ref"; + }; + + dmac0_clk: clock@2 { + compatible = "picochip,pc3x3-gated-clk"; + clock-outputs = "bus"; + picochip,clk-disable-bit = <2>; + clock-frequency = <200000000>; + ref-clock = <&ref_clk>, "ref"; + }; + + dmac1_clk: clock@3 { + compatible = "picochip,pc3x3-gated-clk"; + clock-outputs = "bus"; + picochip,clk-disable-bit = <3>; + clock-frequency = <200000000>; + ref-clock = <&ref_clk>, "ref"; + }; + + ebi_clk: clock@4 { + compatible = "picochip,pc3x3-gated-clk"; + clock-outputs = "bus"; + picochip,clk-disable-bit = <4>; + clock-frequency = <200000000>; + ref-clock = <&ref_clk>, "ref"; + }; + + ipsec_clk: clock@5 { + compatible = "picochip,pc3x3-gated-clk"; + clock-outputs = "bus"; + picochip,clk-disable-bit = <5>; + clock-frequency = <200000000>; + ref-clock = <&ref_clk>, "ref"; + }; + + l2_clk: clock@6 { + compatible = "picochip,pc3x3-gated-clk"; + clock-outputs = "bus"; + picochip,clk-disable-bit = <6>; + clock-frequency = <200000000>; + ref-clock = <&ref_clk>, "ref"; + }; + + trng_clk: clock@7 { + compatible = "picochip,pc3x3-gated-clk"; + clock-outputs = "bus"; + picochip,clk-disable-bit = <7>; + clock-frequency = <200000000>; + ref-clock = <&ref_clk>, "ref"; + }; + + fuse_clk: clock@8 { + compatible = "picochip,pc3x3-gated-clk"; + clock-outputs = "bus"; + picochip,clk-disable-bit = <8>; + clock-frequency = <200000000>; + ref-clock = <&ref_clk>, "ref"; + }; + + otp_clk: clock@9 { + compatible = "picochip,pc3x3-gated-clk"; + clock-outputs = "bus"; + picochip,clk-disable-bit = <9>; + clock-frequency = <200000000>; + ref-clock = <&ref_clk>, "ref"; + }; + }; + + arm_clk: clock@11 { + compatible = "picochip,pc3x3-pll"; + reg = <0x800a0050 0x8>; + picochip,min-freq = <140000000>; + picochip,max-freq = <700000000>; + ref-clock = <&ref_clk>, "ref"; + clock-outputs = "cpu"; + }; + + pclk: clock@12 { + compatible = "fixed-clock"; + clock-outputs = "bus", "pclk"; + clock-frequency = <200000000>; + ref-clock = <&ref_clk>, "ref"; + }; + }; + + paxi { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x80000000 0x400000>; + + emac: gem@30000 { + compatible = "cadence,gem"; + reg = <0x30000 0x10000>; + interrupt-parent = <&vic0>; + interrupts = <31>; + }; + + dmac1: dmac@40000 { + compatible = "snps,dw-dmac"; + reg = <0x40000 0x10000>; + interrupt-parent = <&vic0>; + interrupts = <25>; + }; + + dmac2: dmac@50000 { + compatible = "snps,dw-dmac"; + reg = <0x50000 0x10000>; + interrupt-parent = <&vic0>; + interrupts = <26>; + }; + + vic0: interrupt-controller@60000 { + compatible = "arm,pl192-vic"; + interrupt-controller; + reg = <0x60000 0x1000>; + #interrupt-cells = <1>; + }; + + vic1: interrupt-controller@64000 { + compatible = "arm,pl192-vic"; + interrupt-controller; + reg = <0x64000 0x1000>; + #interrupt-cells = <1>; + }; + + fuse: picoxcell-fuse@80000 { + compatible = "picoxcell,fuse-pc3x3"; + reg = <0x80000 0x10000>; + }; + + ssi: picoxcell-spi@90000 { + compatible = "picoxcell,spi"; + reg = <0x90000 0x10000>; + interrupt-parent = <&vic0>; + interrupts = <10>; + }; + + ipsec: spacc@100000 { + compatible = "picochip,spacc-ipsec"; + reg = <0x100000 0x10000>; + interrupt-parent = <&vic0>; + interrupts = <24>; + ref-clock = <&ipsec_clk>, "ref"; + }; + + srtp: spacc@140000 { + compatible = "picochip,spacc-srtp"; + reg = <0x140000 0x10000>; + interrupt-parent = <&vic0>; + interrupts = <23>; + }; + + l2_engine: spacc@180000 { + compatible = "picochip,spacc-l2"; + reg = <0x180000 0x10000>; + interrupt-parent = <&vic0>; + interrupts = <22>; + ref-clock = <&l2_clk>, "ref"; + }; + + apb { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x200000 0x80000>; + + rtc0: rtc@00000 { + compatible = "picochip,pc3x2-rtc"; + clock-freq = <200000000>; + reg = <0x00000 0xf>; + interrupt-parent = <&vic0>; + interrupts = <8>; + }; + + timer0: timer@10000 { + compatible = "picochip,pc3x2-timer"; + interrupt-parent = <&vic0>; + interrupts = <4>; + clock-freq = <200000000>; + reg = <0x10000 0x14>; + }; + + timer1: timer@10014 { + compatible = "picochip,pc3x2-timer"; + interrupt-parent = <&vic0>; + interrupts = <5>; + clock-freq = <200000000>; + reg = <0x10014 0x14>; + }; + + gpio: gpio@20000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x20000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + reg-io-width = <4>; + + banka: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + gpio-generic,nr-gpio = <8>; + + regoffset-dat = <0x50>; + regoffset-set = <0x00>; + regoffset-dirout = <0x04>; + }; + + bankb: gpio-controller@1 { + compatible = "snps,dw-apb-gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + gpio-generic,nr-gpio = <16>; + + regoffset-dat = <0x54>; + regoffset-set = <0x0c>; + regoffset-dirout = <0x10>; + }; + + bankd: gpio-controller@2 { + compatible = "snps,dw-apb-gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + gpio-generic,nr-gpio = <30>; + + regoffset-dat = <0x5c>; + regoffset-set = <0x24>; + regoffset-dirout = <0x28>; + }; + }; + + uart0: uart@30000 { + compatible = "snps,dw-apb-uart"; + reg = <0x30000 0x1000>; + interrupt-parent = <&vic1>; + interrupts = <10>; + clock-frequency = <3686400>; + reg-shift = <2>; + reg-io-width = <4>; + }; + + uart1: uart@40000 { + compatible = "snps,dw-apb-uart"; + reg = <0x40000 0x1000>; + interrupt-parent = <&vic1>; + interrupts = <9>; + clock-frequency = <3686400>; + reg-shift = <2>; + reg-io-width = <4>; + }; + + wdog: watchdog@50000 { + compatible = "snps,dw-apb-wdg"; + reg = <0x50000 0x10000>; + interrupt-parent = <&vic0>; + interrupts = <11>; + bus-clock = <&pclk>, "bus"; + }; + + timer2: timer@60000 { + compatible = "picochip,pc3x2-timer"; + interrupt-parent = <&vic0>; + interrupts = <6>; + clock-freq = <200000000>; + reg = <0x60000 0x14>; + }; + + timer3: timer@60014 { + compatible = "picochip,pc3x2-timer"; + interrupt-parent = <&vic0>; + interrupts = <7>; + clock-freq = <200000000>; + reg = <0x60014 0x14>; + }; + }; + }; + + rwid-axi { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges; + + ebi@50000000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0x40000000 0x08000000 + 1 0 0x48000000 0x08000000 + 2 0 0x50000000 0x08000000 + 3 0 0x58000000 0x08000000>; + }; + + axi2pico@c0000000 { + compatible = "picochip,axi2pico-pc3x3"; + reg = <0xc0000000 0x10000>; + interrupt-parent = <&vic0>; + interrupts = <13 14 15 16 17 18 19 20 21>; + }; + + otp@ffff8000 { + compatible = "picochip,otp-pc3x3"; + reg = <0xffff8000 0x8000>; + }; + }; +}; -- cgit v1.2.3 From a14bf143b317f9c0944bc7aedfd85c07b3b04150 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Mon, 1 Aug 2011 14:25:24 +0100 Subject: picoxcell: add the DTS for the PC7302 board The PC7302 board can be populated with either a PC3X2 or PC3X3 device. Add DTS files for both variants of the PC7302. v3: - remove bootargs from dts files Signed-off-by: Jamie Iles --- arch/arm/boot/dts/picoxcell-pc7302-pc3x2.dts | 86 ++++++++++++++++++++++++++ arch/arm/boot/dts/picoxcell-pc7302-pc3x3.dts | 92 ++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 arch/arm/boot/dts/picoxcell-pc7302-pc3x2.dts create mode 100644 arch/arm/boot/dts/picoxcell-pc7302-pc3x3.dts (limited to 'arch') diff --git a/arch/arm/boot/dts/picoxcell-pc7302-pc3x2.dts b/arch/arm/boot/dts/picoxcell-pc7302-pc3x2.dts new file mode 100644 index 000000000000..1297414dd649 --- /dev/null +++ b/arch/arm/boot/dts/picoxcell-pc7302-pc3x2.dts @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2011 Picochip, Jamie Iles + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +/dts-v1/; +/include/ "picoxcell-pc3x2.dtsi" +/ { + model = "Picochip PC7302 (PC3X2)"; + compatible = "picochip,pc7302-pc3x2", "picochip,pc3x2"; + + memory { + device_type = "memory"; + reg = <0x0 0x08000000>; + }; + + chosen { + linux,stdout-path = &uart0; + }; + + clocks { + ref_clk: clock@1 { + compatible = "fixed-clock"; + clock-outputs = "ref"; + clock-frequency = <20000000>; + }; + }; + + rwid-axi { + ebi@50000000 { + nand: gpio-nand@2,0 { + compatible = "gpio-control-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <2 0x0000 0x1000>; + bus-clock = <&pclk>, "bus"; + gpio-control-nand,io-sync-reg = + <0x00000000 0x80220000>; + + gpios = <&banka 1 0 /* rdy */ + &banka 2 0 /* nce */ + &banka 3 0 /* ale */ + &banka 4 0 /* cle */ + 0 /* nwp */>; + + boot@100000 { + label = "Boot"; + reg = <0x100000 0x80000>; + }; + + redundant-boot@200000 { + label = "Redundant Boot"; + reg = <0x200000 0x80000>; + }; + + boot-env@300000 { + label = "Boot Evironment"; + reg = <0x300000 0x20000>; + }; + + redundant-boot-env@320000 { + label = "Redundant Boot Environment"; + reg = <0x300000 0x20000>; + }; + + kernel@380000 { + label = "Kernel"; + reg = <0x380000 0x800000>; + }; + + fs@b80000 { + label = "File System"; + reg = <0xb80000 0xf480000>; + }; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/picoxcell-pc7302-pc3x3.dts b/arch/arm/boot/dts/picoxcell-pc7302-pc3x3.dts new file mode 100644 index 000000000000..9e317a4f431c --- /dev/null +++ b/arch/arm/boot/dts/picoxcell-pc7302-pc3x3.dts @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2011 Picochip, Jamie Iles + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +/dts-v1/; +/include/ "picoxcell-pc3x3.dtsi" +/ { + model = "Picochip PC7302 (PC3X3)"; + compatible = "picochip,pc7302-pc3x3", "picochip,pc3x3"; + + memory { + device_type = "memory"; + reg = <0x0 0x08000000>; + }; + + chosen { + linux,stdout-path = &uart0; + }; + + clocks { + ref_clk: clock@10 { + compatible = "fixed-clock"; + clock-outputs = "ref"; + clock-frequency = <20000000>; + }; + + clkgate: clkgate@800a0048 { + clock@4 { + picochip,clk-no-disable; + }; + }; + }; + + rwid-axi { + ebi@50000000 { + nand: gpio-nand@2,0 { + compatible = "gpio-control-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <2 0x0000 0x1000>; + bus-clock = <&ebi_clk>, "bus"; + gpio-control-nand,io-sync-reg = + <0x00000000 0x80220000>; + + gpios = <&banka 1 0 /* rdy */ + &banka 2 0 /* nce */ + &banka 3 0 /* ale */ + &banka 4 0 /* cle */ + 0 /* nwp */>; + + boot@100000 { + label = "Boot"; + reg = <0x100000 0x80000>; + }; + + redundant-boot@200000 { + label = "Redundant Boot"; + reg = <0x200000 0x80000>; + }; + + boot-env@300000 { + label = "Boot Evironment"; + reg = <0x300000 0x20000>; + }; + + redundant-boot-env@320000 { + label = "Redundant Boot Environment"; + reg = <0x300000 0x20000>; + }; + + kernel@380000 { + label = "Kernel"; + reg = <0x380000 0x800000>; + }; + + fs@b80000 { + label = "File System"; + reg = <0xb80000 0xf480000>; + }; + }; + }; + }; +}; -- cgit v1.2.3 From 6190303b4e55ce11774d036f9b90d204223caa1e Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Fri, 16 Sep 2011 14:26:18 +0100 Subject: picoxcell: remove custom ioremap implementation Nicolas Pitre's generic ioremap() patch set means that we don't need this any more. Signed-off-by: Jamie Iles --- arch/arm/mach-picoxcell/include/mach/io.h | 7 ------- arch/arm/mach-picoxcell/include/mach/vmalloc.h | 18 ------------------ arch/arm/mach-picoxcell/io.c | 24 ------------------------ 3 files changed, 49 deletions(-) delete mode 100644 arch/arm/mach-picoxcell/include/mach/vmalloc.h (limited to 'arch') diff --git a/arch/arm/mach-picoxcell/include/mach/io.h b/arch/arm/mach-picoxcell/include/mach/io.h index a863b0f6eeec..7573ec7d10a3 100644 --- a/arch/arm/mach-picoxcell/include/mach/io.h +++ b/arch/arm/mach-picoxcell/include/mach/io.h @@ -19,11 +19,4 @@ /* No PCI possible on picoxcell. */ #define __mem_pci(a) (a) -#define __arch_ioremap picoxcell_ioremap -#define __arch_iounmap picoxcell_iounmap - -extern void __iomem *picoxcell_ioremap(unsigned long phys, size_t size, - unsigned int type); -extern void picoxcell_iounmap(volatile void __iomem *addr); - #endif /* __ASM_ARM_ARCH_IO_H */ diff --git a/arch/arm/mach-picoxcell/include/mach/vmalloc.h b/arch/arm/mach-picoxcell/include/mach/vmalloc.h deleted file mode 100644 index 62559e30888a..000000000000 --- a/arch/arm/mach-picoxcell/include/mach/vmalloc.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2011 Picochip Ltd., Jamie Iles - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#define VMALLOC_END 0xFE000000UL diff --git a/arch/arm/mach-picoxcell/io.c b/arch/arm/mach-picoxcell/io.c index 935a2fae62e6..39e9b9e8cc37 100644 --- a/arch/arm/mach-picoxcell/io.c +++ b/arch/arm/mach-picoxcell/io.c @@ -30,27 +30,3 @@ void __init picoxcell_map_io(void) iotable_init(&io_map, 1); } - -void __iomem *picoxcell_ioremap(unsigned long p, size_t size, - unsigned int type) -{ - if (unlikely(size == 0)) - return NULL; - - if (p >= PICOXCELL_PERIPH_BASE && - p < PICOXCELL_PERIPH_BASE + PICOXCELL_PERIPH_LENGTH) - return IO_ADDRESS(p); - - return __arm_ioremap_caller(p, size, type, - __builtin_return_address(0)); -} -EXPORT_SYMBOL_GPL(picoxcell_ioremap); - -void picoxcell_iounmap(volatile void __iomem *addr) -{ - unsigned long virt = (unsigned long)addr; - - if (virt >= VMALLOC_START && virt < VMALLOC_END) - __iounmap(addr); -} -EXPORT_SYMBOL_GPL(picoxcell_iounmap); -- cgit v1.2.3 From 76780127914d5dc69a458eda5e471e65a5fd3dc9 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Tue, 4 Oct 2011 21:18:34 +0100 Subject: picoxcell: add a definition of VMALLOC_END Nicolas Pitre's vmalloc cleanup series didn't get merged in this cycle so picoxcell is missing a VMALLOC_END definition. Signed-off-by: Jamie Iles --- arch/arm/mach-picoxcell/include/mach/vmalloc.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 arch/arm/mach-picoxcell/include/mach/vmalloc.h (limited to 'arch') diff --git a/arch/arm/mach-picoxcell/include/mach/vmalloc.h b/arch/arm/mach-picoxcell/include/mach/vmalloc.h new file mode 100644 index 000000000000..0216cc4b1f0b --- /dev/null +++ b/arch/arm/mach-picoxcell/include/mach/vmalloc.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2011 Picochip Ltd., Jamie Iles + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ +#define VMALLOC_END 0xfe000000UL -- cgit v1.2.3 From fae2b89ab13f6181cb418d788b66a44758cc71d4 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 25 Aug 2011 08:14:52 -0500 Subject: ARM: l2x0: add empty l2x0_of_init Add empty version of l2x0_of_init for when CONFIG_CACHE_L2X0 is not selected. Signed-off-by: Rob Herring Acked-by: Barry Song <21cnbao@gmail.com> Reviewed-by: Shawn Guo --- arch/arm/include/asm/hardware/cache-l2x0.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h index 434edccdf7f3..1db1143a9483 100644 --- a/arch/arm/include/asm/hardware/cache-l2x0.h +++ b/arch/arm/include/asm/hardware/cache-l2x0.h @@ -102,7 +102,14 @@ #ifndef __ASSEMBLY__ extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask); +#if defined(CONFIG_CACHE_L2X0) && defined(CONFIG_OF) extern int l2x0_of_init(__u32 aux_val, __u32 aux_mask); +#else +static inline int l2x0_of_init(__u32 aux_val, __u32 aux_mask) +{ + return -ENODEV; +} +#endif struct l2x0_regs { unsigned long phy_base; @@ -121,6 +128,6 @@ struct l2x0_regs { extern struct l2x0_regs l2x0_saved_regs; -#endif +#endif /* __ASSEMBLY__ */ #endif -- cgit v1.2.3 From 253d7addbcb06acc90eb722f122d32a6ccbf67a7 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 10 Aug 2011 15:22:11 -0500 Subject: ARM: highbank: add devicetree source This adds the devicetree source and documentation for the Calxeda highbank platform. Signed-off-by: Rob Herring Reviewed-by: Jamie Iles Reviewed-by: Shawn Guo --- Documentation/devicetree/bindings/arm/calxeda.txt | 8 + arch/arm/boot/dts/highbank.dts | 198 ++++++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/calxeda.txt create mode 100644 arch/arm/boot/dts/highbank.dts (limited to 'arch') diff --git a/Documentation/devicetree/bindings/arm/calxeda.txt b/Documentation/devicetree/bindings/arm/calxeda.txt new file mode 100644 index 000000000000..4755caaccba6 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/calxeda.txt @@ -0,0 +1,8 @@ +Calxeda Highbank Platforms Device Tree Bindings +----------------------------------------------- + +Boards with Calxeda Cortex-A9 based Highbank SOC shall have the following +properties. + +Required root node properties: + - compatible = "calxeda,highbank"; diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts new file mode 100644 index 000000000000..aeb1a7578fad --- /dev/null +++ b/arch/arm/boot/dts/highbank.dts @@ -0,0 +1,198 @@ +/* + * Copyright 2011 Calxeda, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ + +/dts-v1/; + +/* First 4KB has pen for secondary cores. */ +/memreserve/ 0x00000000 0x0001000; + +/ { + model = "Calxeda Highbank"; + compatible = "calxeda,highbank"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a9"; + reg = <0>; + next-level-cache = <&L2>; + }; + + cpu@1 { + compatible = "arm,cortex-a9"; + reg = <1>; + next-level-cache = <&L2>; + }; + + cpu@2 { + compatible = "arm,cortex-a9"; + reg = <2>; + next-level-cache = <&L2>; + }; + + cpu@3 { + compatible = "arm,cortex-a9"; + reg = <3>; + next-level-cache = <&L2>; + }; + }; + + memory { + name = "memory"; + device_type = "memory"; + reg = <0x00000000 0xff900000>; + }; + + chosen { + bootargs = "console=ttyAMA0"; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + interrupt-parent = <&intc>; + ranges; + + timer@fff10600 { + compatible = "arm,smp-twd"; + reg = <0xfff10600 0x20>; + interrupts = <1 13 0xf04>; + }; + + watchdog@fff10620 { + compatible = "arm,cortex-a9-wdt"; + reg = <0xfff10620 0x20>; + interrupts = <1 14 0xf04>; + }; + + intc: interrupt-controller@fff11000 { + compatible = "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + #size-cells = <0>; + #address-cells = <1>; + interrupt-controller; + interrupt-parent; + reg = <0xfff11000 0x1000>, + <0xfff10100 0x100>; + }; + + L2: l2-cache { + compatible = "arm,pl310-cache"; + reg = <0xfff12000 0x1000>; + interrupts = <0 70 4>; + cache-unified; + cache-level = <2>; + }; + + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupts = <0 76 4 0 75 4 0 74 4 0 73 4>; + }; + + sata@ffe08000 { + compatible = "calxeda,hb-ahci"; + reg = <0xffe08000 0x10000>; + interrupts = <0 83 4>; + }; + + sdhci@ffe0e000 { + compatible = "calxeda,hb-sdhci"; + reg = <0xffe0e000 0x1000>; + interrupts = <0 90 4>; + }; + + ipc@fff20000 { + compatible = "arm,pl320", "arm,primecell"; + reg = <0xfff20000 0x1000>; + interrupts = <0 7 4>; + }; + + gpioe: gpio@fff30000 { + #gpio-cells = <2>; + compatible = "arm,pl061", "arm,primecell"; + gpio-controller; + reg = <0xfff30000 0x1000>; + interrupts = <0 14 4>; + }; + + gpiof: gpio@fff31000 { + #gpio-cells = <2>; + compatible = "arm,pl061", "arm,primecell"; + gpio-controller; + reg = <0xfff31000 0x1000>; + interrupts = <0 15 4>; + }; + + gpiog: gpio@fff32000 { + #gpio-cells = <2>; + compatible = "arm,pl061", "arm,primecell"; + gpio-controller; + reg = <0xfff32000 0x1000>; + interrupts = <0 16 4>; + }; + + gpioh: gpio@fff33000 { + #gpio-cells = <2>; + compatible = "arm,pl061", "arm,primecell"; + gpio-controller; + reg = <0xfff33000 0x1000>; + interrupts = <0 17 4>; + }; + + timer { + compatible = "arm,sp804", "arm,primecell"; + reg = <0xfff34000 0x1000>; + interrupts = <0 18 4>; + }; + + rtc@fff35000 { + compatible = "arm,pl031", "arm,primecell"; + reg = <0xfff35000 0x1000>; + interrupts = <0 19 4>; + }; + + serial@fff36000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0xfff36000 0x1000>; + interrupts = <0 20 4>; + }; + + smic@fff3a000 { + compatible = "ipmi-smic"; + device_type = "ipmi"; + reg = <0xfff3a000 0x1000>; + interrupts = <0 24 4>; + reg-size = <4>; + reg-spacing = <4>; + }; + + sregs@fff3c000 { + compatible = "calxeda,hb-sregs"; + reg = <0xfff3c000 0x1000>; + }; + + dma@fff3d000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0xfff3d000 0x1000>; + interrupts = <0 92 4>; + }; + }; +}; -- cgit v1.2.3 From 220e6cf7b793d702596506a8c4bf1f4fd4040df1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 7 Jun 2011 10:02:55 -0500 Subject: ARM: add Highbank core platform support This adds basic support for the Calxeda Highbank platform. Signed-off-by: Rob Herring Reviewed-by: Jamie Iles Reviewed-by: Shawn Guo --- arch/arm/Kconfig | 14 +++ arch/arm/Kconfig.debug | 7 ++ arch/arm/Makefile | 1 + arch/arm/mach-highbank/Makefile | 2 + arch/arm/mach-highbank/Makefile.boot | 1 + arch/arm/mach-highbank/clock.c | 62 +++++++++ arch/arm/mach-highbank/core.h | 9 ++ arch/arm/mach-highbank/highbank.c | 145 ++++++++++++++++++++++ arch/arm/mach-highbank/include/mach/debug-macro.S | 19 +++ arch/arm/mach-highbank/include/mach/entry-macro.S | 7 ++ arch/arm/mach-highbank/include/mach/gpio.h | 1 + arch/arm/mach-highbank/include/mach/io.h | 7 ++ arch/arm/mach-highbank/include/mach/irqs.h | 6 + arch/arm/mach-highbank/include/mach/memory.h | 1 + arch/arm/mach-highbank/include/mach/system.h | 26 ++++ arch/arm/mach-highbank/include/mach/timex.h | 6 + arch/arm/mach-highbank/include/mach/uncompress.h | 9 ++ arch/arm/mach-highbank/include/mach/vmalloc.h | 1 + arch/arm/mach-highbank/lluart.c | 34 +++++ arch/arm/mach-highbank/sysregs.h | 52 ++++++++ arch/arm/mach-highbank/system.c | 33 +++++ arch/arm/mm/Kconfig | 2 +- 22 files changed, 444 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-highbank/Makefile create mode 100644 arch/arm/mach-highbank/Makefile.boot create mode 100644 arch/arm/mach-highbank/clock.c create mode 100644 arch/arm/mach-highbank/core.h create mode 100644 arch/arm/mach-highbank/highbank.c create mode 100644 arch/arm/mach-highbank/include/mach/debug-macro.S create mode 100644 arch/arm/mach-highbank/include/mach/entry-macro.S create mode 100644 arch/arm/mach-highbank/include/mach/gpio.h create mode 100644 arch/arm/mach-highbank/include/mach/io.h create mode 100644 arch/arm/mach-highbank/include/mach/irqs.h create mode 100644 arch/arm/mach-highbank/include/mach/memory.h create mode 100644 arch/arm/mach-highbank/include/mach/system.h create mode 100644 arch/arm/mach-highbank/include/mach/timex.h create mode 100644 arch/arm/mach-highbank/include/mach/uncompress.h create mode 100644 arch/arm/mach-highbank/include/mach/vmalloc.h create mode 100644 arch/arm/mach-highbank/lluart.c create mode 100644 arch/arm/mach-highbank/sysregs.h create mode 100644 arch/arm/mach-highbank/system.c (limited to 'arch') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 7bbb03558d2c..887b818bd667 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -330,6 +330,20 @@ config ARCH_BCMRING help Support for Broadcom's BCMRing platform. +config ARCH_HIGHBANK + bool "Calxeda Highbank-based" + select ARCH_WANT_OPTIONAL_GPIOLIB + select ARM_AMBA + select ARM_GIC + select ARM_TIMER_SP804 + select CLKDEV_LOOKUP + select CPU_V7 + select GENERIC_CLOCKEVENTS + select HAVE_ARM_SCU + select USE_OF + help + Support for the Calxeda Highbank SoC based boards. + config ARCH_CLPS711X bool "Cirrus Logic CLPS711x/EP721x-based" select CPU_ARM720T diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 0887801c324f..4bb7eb90f070 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -128,6 +128,13 @@ choice Say Y here if you want the debug print routines to direct their output to the second serial port on these devices. + config DEBUG_HIGHBANK_UART + bool "Kernel low-level debugging messages via Highbank UART" + depends on ARCH_HIGHBANK + help + Say Y here if you want the debug print routines to direct + their output to the UART on Highbank based devices. + endchoice config EARLY_PRINTK diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 5665c2a3b652..98c3c22572e4 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -144,6 +144,7 @@ machine-$(CONFIG_ARCH_EBSA110) := ebsa110 machine-$(CONFIG_ARCH_EP93XX) := ep93xx machine-$(CONFIG_ARCH_GEMINI) := gemini machine-$(CONFIG_ARCH_H720X) := h720x +machine-$(CONFIG_ARCH_HIGHBANK) := highbank machine-$(CONFIG_ARCH_INTEGRATOR) := integrator machine-$(CONFIG_ARCH_IOP13XX) := iop13xx machine-$(CONFIG_ARCH_IOP32X) := iop32x diff --git a/arch/arm/mach-highbank/Makefile b/arch/arm/mach-highbank/Makefile new file mode 100644 index 000000000000..da7f81a69530 --- /dev/null +++ b/arch/arm/mach-highbank/Makefile @@ -0,0 +1,2 @@ +obj-y := clock.o highbank.o system.o +obj-$(CONFIG_DEBUG_HIGHBANK_UART) += lluart.o diff --git a/arch/arm/mach-highbank/Makefile.boot b/arch/arm/mach-highbank/Makefile.boot new file mode 100644 index 000000000000..dae9661a7689 --- /dev/null +++ b/arch/arm/mach-highbank/Makefile.boot @@ -0,0 +1 @@ +zreladdr-y := 0x00008000 diff --git a/arch/arm/mach-highbank/clock.c b/arch/arm/mach-highbank/clock.c new file mode 100644 index 000000000000..c25a2ae4fde1 --- /dev/null +++ b/arch/arm/mach-highbank/clock.c @@ -0,0 +1,62 @@ +/* + * Copyright 2011 Calxeda, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ +#include +#include +#include +#include +#include + +struct clk { + unsigned long rate; +}; + +int clk_enable(struct clk *clk) +{ + return 0; +} + +void clk_disable(struct clk *clk) +{} + +unsigned long clk_get_rate(struct clk *clk) +{ + return clk->rate; +} + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + return clk->rate; +} + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + return 0; +} + +static struct clk eclk = { .rate = 200000000 }; +static struct clk pclk = { .rate = 150000000 }; + +static struct clk_lookup lookups[] = { + { .clk = &pclk, .con_id = "apb_pclk", }, + { .clk = &pclk, .dev_id = "sp804", }, + { .clk = &eclk, .dev_id = "ffe0e000.sdhci", }, + { .clk = &pclk, .dev_id = "fff36000.serial", }, +}; + +void __init highbank_clocks_init(void) +{ + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); +} diff --git a/arch/arm/mach-highbank/core.h b/arch/arm/mach-highbank/core.h new file mode 100644 index 000000000000..7e33fc94cd1e --- /dev/null +++ b/arch/arm/mach-highbank/core.h @@ -0,0 +1,9 @@ +extern void highbank_set_cpu_jump(int cpu, void *jump_addr); +extern void highbank_clocks_init(void); +extern void __iomem *scu_base_addr; +#ifdef CONFIG_DEBUG_HIGHBANK_UART +extern void highbank_lluart_map_io(void); +#else +static inline void highbank_lluart_map_io(void) {} +#endif + diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c new file mode 100644 index 000000000000..b82dcf08e747 --- /dev/null +++ b/arch/arm/mach-highbank/highbank.c @@ -0,0 +1,145 @@ +/* + * Copyright 2010-2011 Calxeda, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core.h" +#include "sysregs.h" + +void __iomem *sregs_base; + +#define HB_SCU_VIRT_BASE 0xfee00000 +void __iomem *scu_base_addr = ((void __iomem *)(HB_SCU_VIRT_BASE)); + +static struct map_desc scu_io_desc __initdata = { + .virtual = HB_SCU_VIRT_BASE, + .pfn = 0, /* run-time */ + .length = SZ_4K, + .type = MT_DEVICE, +}; + +static void __init highbank_scu_map_io(void) +{ + unsigned long base; + + /* Get SCU base */ + asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base)); + + scu_io_desc.pfn = __phys_to_pfn(base); + iotable_init(&scu_io_desc, 1); +} + +static void __init highbank_map_io(void) +{ + highbank_scu_map_io(); + highbank_lluart_map_io(); +} + +#define HB_JUMP_TABLE_PHYS(cpu) (0x40 + (0x10 * (cpu))) +#define HB_JUMP_TABLE_VIRT(cpu) phys_to_virt(HB_JUMP_TABLE_PHYS(cpu)) + +void highbank_set_cpu_jump(int cpu, void *jump_addr) +{ + writel(BSYM(virt_to_phys(jump_addr)), HB_JUMP_TABLE_VIRT(cpu)); + __cpuc_flush_dcache_area(HB_JUMP_TABLE_VIRT(cpu), 16); + outer_clean_range(HB_JUMP_TABLE_PHYS(cpu), + HB_JUMP_TABLE_PHYS(cpu) + 15); +} + +const static struct of_device_id irq_match[] = { + { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, + {} +}; + +static void __init highbank_init_irq(void) +{ + of_irq_init(irq_match); + l2x0_of_init(0, ~0UL); +} + +static void __init highbank_timer_init(void) +{ + int irq; + struct device_node *np; + void __iomem *timer_base; + + /* Map system registers */ + np = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs"); + sregs_base = of_iomap(np, 0); + WARN_ON(!sregs_base); + + np = of_find_compatible_node(NULL, NULL, "arm,sp804"); + timer_base = of_iomap(np, 0); + WARN_ON(!timer_base); + irq = irq_of_parse_and_map(np, 0); + + highbank_clocks_init(); + + sp804_clocksource_init(timer_base + 0x20, "timer1"); + sp804_clockevents_init(timer_base, irq, "timer0"); +} + +static struct sys_timer highbank_timer = { + .init = highbank_timer_init, +}; + +static void highbank_power_off(void) +{ + hignbank_set_pwr_shutdown(); + scu_power_mode(scu_base_addr, SCU_PM_POWEROFF); + + while (1) + cpu_do_idle(); +} + +static void __init highbank_init(void) +{ + pm_power_off = highbank_power_off; + + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); +} + +static const char *highbank_match[] __initconst = { + "calxeda,highbank", + NULL, +}; + +DT_MACHINE_START(HIGHBANK, "Highbank") + .map_io = highbank_map_io, + .init_irq = highbank_init_irq, + .timer = &highbank_timer, + .init_machine = highbank_init, + .dt_compat = highbank_match, +MACHINE_END diff --git a/arch/arm/mach-highbank/include/mach/debug-macro.S b/arch/arm/mach-highbank/include/mach/debug-macro.S new file mode 100644 index 000000000000..cb57fe5bcd04 --- /dev/null +++ b/arch/arm/mach-highbank/include/mach/debug-macro.S @@ -0,0 +1,19 @@ +/* + * Debugging macro include header + * + * Copyright (C) 1994-1999 Russell King + * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + .macro addruart,rp,rv,tmp + movw \rv, #0x6000 + movt \rv, #0xfee3 + movw \rp, #0x6000 + movt \rp, #0xfff3 + .endm + +#include diff --git a/arch/arm/mach-highbank/include/mach/entry-macro.S b/arch/arm/mach-highbank/include/mach/entry-macro.S new file mode 100644 index 000000000000..73c11297509e --- /dev/null +++ b/arch/arm/mach-highbank/include/mach/entry-macro.S @@ -0,0 +1,7 @@ +#include + + .macro disable_fiq + .endm + + .macro arch_ret_to_user, tmp1, tmp2 + .endm diff --git a/arch/arm/mach-highbank/include/mach/gpio.h b/arch/arm/mach-highbank/include/mach/gpio.h new file mode 100644 index 000000000000..40a8c178f10d --- /dev/null +++ b/arch/arm/mach-highbank/include/mach/gpio.h @@ -0,0 +1 @@ +/* empty */ diff --git a/arch/arm/mach-highbank/include/mach/io.h b/arch/arm/mach-highbank/include/mach/io.h new file mode 100644 index 000000000000..70cfa3ba7697 --- /dev/null +++ b/arch/arm/mach-highbank/include/mach/io.h @@ -0,0 +1,7 @@ +#ifndef __MACH_IO_H +#define __MACH_IO_H + +#define __io(a) ({ (void)(a); __typesafe_io(0); }) +#define __mem_pci(a) (a) + +#endif diff --git a/arch/arm/mach-highbank/include/mach/irqs.h b/arch/arm/mach-highbank/include/mach/irqs.h new file mode 100644 index 000000000000..9746aab14e9a --- /dev/null +++ b/arch/arm/mach-highbank/include/mach/irqs.h @@ -0,0 +1,6 @@ +#ifndef __MACH_IRQS_H +#define __MACH_IRQS_H + +#define NR_IRQS 192 + +#endif diff --git a/arch/arm/mach-highbank/include/mach/memory.h b/arch/arm/mach-highbank/include/mach/memory.h new file mode 100644 index 000000000000..40a8c178f10d --- /dev/null +++ b/arch/arm/mach-highbank/include/mach/memory.h @@ -0,0 +1 @@ +/* empty */ diff --git a/arch/arm/mach-highbank/include/mach/system.h b/arch/arm/mach-highbank/include/mach/system.h new file mode 100644 index 000000000000..7e8192296cae --- /dev/null +++ b/arch/arm/mach-highbank/include/mach/system.h @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2011 Calxeda, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ +#ifndef __MACH_SYSTEM_H +#define __MACH_SYSTEM_H + +static inline void arch_idle(void) +{ + cpu_do_idle(); +} + +extern void arch_reset(char mode, const char *cmd); + +#endif diff --git a/arch/arm/mach-highbank/include/mach/timex.h b/arch/arm/mach-highbank/include/mach/timex.h new file mode 100644 index 000000000000..88dac7a55a97 --- /dev/null +++ b/arch/arm/mach-highbank/include/mach/timex.h @@ -0,0 +1,6 @@ +#ifndef __MACH_TIMEX_H +#define __MACH_TIMEX_H + +#define CLOCK_TICK_RATE 1000000 + +#endif diff --git a/arch/arm/mach-highbank/include/mach/uncompress.h b/arch/arm/mach-highbank/include/mach/uncompress.h new file mode 100644 index 000000000000..bbe20e696325 --- /dev/null +++ b/arch/arm/mach-highbank/include/mach/uncompress.h @@ -0,0 +1,9 @@ +#ifndef __MACH_UNCOMPRESS_H +#define __MACH_UNCOMPRESS_H + +#define putc(c) +#define flush() +#define arch_decomp_setup() +#define arch_decomp_wdog() + +#endif diff --git a/arch/arm/mach-highbank/include/mach/vmalloc.h b/arch/arm/mach-highbank/include/mach/vmalloc.h new file mode 100644 index 000000000000..1969e954277a --- /dev/null +++ b/arch/arm/mach-highbank/include/mach/vmalloc.h @@ -0,0 +1 @@ +#define VMALLOC_END 0xFEE00000UL diff --git a/arch/arm/mach-highbank/lluart.c b/arch/arm/mach-highbank/lluart.c new file mode 100644 index 000000000000..371575019f33 --- /dev/null +++ b/arch/arm/mach-highbank/lluart.c @@ -0,0 +1,34 @@ +/* + * Copyright 2011 Calxeda, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ +#include +#include +#include +#include + +#define HB_DEBUG_LL_PHYS_BASE 0xfff36000 +#define HB_DEBUG_LL_VIRT_BASE 0xfee36000 + +static struct map_desc lluart_io_desc __initdata = { + .virtual = HB_DEBUG_LL_VIRT_BASE, + .pfn = __phys_to_pfn(HB_DEBUG_LL_PHYS_BASE), + .length = SZ_4K, + .type = MT_DEVICE, +}; + +void __init highbank_lluart_map_io(void) +{ + iotable_init(&lluart_io_desc, 1); +} diff --git a/arch/arm/mach-highbank/sysregs.h b/arch/arm/mach-highbank/sysregs.h new file mode 100644 index 000000000000..0e913389f445 --- /dev/null +++ b/arch/arm/mach-highbank/sysregs.h @@ -0,0 +1,52 @@ +/* + * Copyright 2011 Calxeda, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ +#ifndef _MACH_HIGHBANK__SYSREGS_H_ +#define _MACH_HIGHBANK__SYSREGS_H_ + +#include + +extern void __iomem *sregs_base; + +#define HB_SREG_A9_PWR_REQ 0xf00 +#define HB_SREG_A9_BOOT_STAT 0xf04 +#define HB_SREG_A9_BOOT_DATA 0xf08 + +#define HB_PWR_SUSPEND 0 +#define HB_PWR_SOFT_RESET 1 +#define HB_PWR_HARD_RESET 2 +#define HB_PWR_SHUTDOWN 3 + +static inline void hignbank_set_pwr_suspend(void) +{ + writel(HB_PWR_SUSPEND, sregs_base + HB_SREG_A9_PWR_REQ); +} + +static inline void hignbank_set_pwr_shutdown(void) +{ + writel(HB_PWR_SHUTDOWN, sregs_base + HB_SREG_A9_PWR_REQ); +} + +static inline void hignbank_set_pwr_soft_reset(void) +{ + writel(HB_PWR_SOFT_RESET, sregs_base + HB_SREG_A9_PWR_REQ); +} + +static inline void hignbank_set_pwr_hard_reset(void) +{ + writel(HB_PWR_HARD_RESET, sregs_base + HB_SREG_A9_PWR_REQ); +} + +#endif diff --git a/arch/arm/mach-highbank/system.c b/arch/arm/mach-highbank/system.c new file mode 100644 index 000000000000..53f0c4c5ef1c --- /dev/null +++ b/arch/arm/mach-highbank/system.c @@ -0,0 +1,33 @@ +/* + * Copyright 2011 Calxeda, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ +#include +#include +#include + +#include "core.h" +#include "sysregs.h" + +void arch_reset(char mode, const char *cmd) +{ + if (mode == 'h') + hignbank_set_pwr_hard_reset(); + else + hignbank_set_pwr_soft_reset(); + + scu_power_mode(scu_base_addr, SCU_PM_POWEROFF); + cpu_do_idle(); +} + diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 88633fe01a5d..7d5fff7b3632 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -822,7 +822,7 @@ config CACHE_L2X0 REALVIEW_EB_A9MP || SOC_IMX35 || SOC_IMX31 || MACH_REALVIEW_PBX || \ ARCH_NOMADIK || ARCH_OMAP4 || ARCH_EXYNOS4 || ARCH_TEGRA || \ ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || ARCH_SHMOBILE || \ - ARCH_PRIMA2 || ARCH_ZYNQ || ARCH_CNS3XXX + ARCH_PRIMA2 || ARCH_ZYNQ || ARCH_CNS3XXX || ARCH_HIGHBANK default y select OUTER_CACHE select OUTER_CACHE_SYNC -- cgit v1.2.3 From 6738845783e9113feec22f20834d0e956808da3b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 17 May 2011 21:02:49 -0500 Subject: ARM: highbank: add SMP support This enables SMP support on highbank processor. Signed-off-by: Rob Herring Reviewed-by: Jamie Iles Reviewed-by: Shawn Guo --- arch/arm/Kconfig | 2 +- arch/arm/mach-highbank/Makefile | 2 + arch/arm/mach-highbank/localtimer.c | 40 +++++++++++++++++++ arch/arm/mach-highbank/platsmp.c | 78 +++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-highbank/localtimer.c create mode 100644 arch/arm/mach-highbank/platsmp.c (limited to 'arch') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 887b818bd667..b02e85bb4736 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1416,7 +1416,7 @@ config SMP depends on REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP || \ MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4 || \ ARCH_EXYNOS4 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || \ - ARCH_MSM_SCORPIONMP || ARCH_SHMOBILE + ARCH_MSM_SCORPIONMP || ARCH_SHMOBILE || ARCH_HIGHBANK select USE_GENERIC_SMP_HELPERS select HAVE_ARM_SCU if !ARCH_MSM_SCORPIONMP help diff --git a/arch/arm/mach-highbank/Makefile b/arch/arm/mach-highbank/Makefile index da7f81a69530..89c736ff047f 100644 --- a/arch/arm/mach-highbank/Makefile +++ b/arch/arm/mach-highbank/Makefile @@ -1,2 +1,4 @@ obj-y := clock.o highbank.o system.o obj-$(CONFIG_DEBUG_HIGHBANK_UART) += lluart.o +obj-$(CONFIG_SMP) += platsmp.o +obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o diff --git a/arch/arm/mach-highbank/localtimer.c b/arch/arm/mach-highbank/localtimer.c new file mode 100644 index 000000000000..5a00e7945fdf --- /dev/null +++ b/arch/arm/mach-highbank/localtimer.c @@ -0,0 +1,40 @@ +/* + * Copyright 2010-2011 Calxeda, Inc. + * Based on localtimer.c, Copyright (C) 2002 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ +#include +#include +#include +#include +#include + +#include + +/* + * Setup the local clock events for a CPU. + */ +int __cpuinit local_timer_setup(struct clock_event_device *evt) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "arm,smp-twd"); + if (!twd_base) { + twd_base = of_iomap(np, 0); + WARN_ON(!twd_base); + } + evt->irq = irq_of_parse_and_map(np, 0); + twd_timer_setup(evt); + return 0; +} diff --git a/arch/arm/mach-highbank/platsmp.c b/arch/arm/mach-highbank/platsmp.c new file mode 100644 index 000000000000..d01364c72b45 --- /dev/null +++ b/arch/arm/mach-highbank/platsmp.c @@ -0,0 +1,78 @@ +/* + * Copyright 2010-2011 Calxeda, Inc. + * Based on platsmp.c, Copyright (C) 2002 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ +#include +#include +#include + +#include +#include + +#include "core.h" + +extern void secondary_startup(void); + +void __cpuinit platform_secondary_init(unsigned int cpu) +{ + gic_secondary_init(0); +} + +int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + gic_raise_softirq(cpumask_of(cpu), 0); + return 0; +} + +/* + * Initialise the CPU possible map early - this describes the CPUs + * which may be present or become present in the system. + */ +void __init smp_init_cpus(void) +{ + unsigned int i, ncores; + + ncores = scu_get_core_count(scu_base_addr); + + /* sanity check */ + if (ncores > NR_CPUS) { + printk(KERN_WARNING + "highbank: no. of cores (%d) greater than configured " + "maximum of %d - clipping\n", + ncores, NR_CPUS); + ncores = NR_CPUS; + } + + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); + + set_smp_cross_call(gic_raise_softirq); +} + +void __init platform_smp_prepare_cpus(unsigned int max_cpus) +{ + int i; + + scu_enable(scu_base_addr); + + /* + * Write the address of secondary startup into the jump table + * The cores are in wfi and wait until they receive a soft interrupt + * and a non-zero value to jump to. Then the secondary CPU branches + * to this address. + */ + for (i = 1; i < max_cpus; i++) + highbank_set_cpu_jump(i, secondary_startup); +} -- cgit v1.2.3 From 9680b3d04d27ed90479eb84d2054ddd3deb83d5e Mon Sep 17 00:00:00 2001 From: Martin Bogomolni Date: Mon, 13 Jun 2011 16:50:33 -0500 Subject: ARM: highbank: Add cpu hotplug support This adds cpu hotplug for highbank. On highbank, a core is always reset and boots up the same path as a cold boot. Signed-off-by: Martin Bogomolni Signed-off-by: Rob Herring Reviewed-by: Jamie Iles Reviewed-by: Shawn Guo --- arch/arm/mach-highbank/Makefile | 1 + arch/arm/mach-highbank/hotplug.c | 56 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 arch/arm/mach-highbank/hotplug.c (limited to 'arch') diff --git a/arch/arm/mach-highbank/Makefile b/arch/arm/mach-highbank/Makefile index 89c736ff047f..c45078f820ae 100644 --- a/arch/arm/mach-highbank/Makefile +++ b/arch/arm/mach-highbank/Makefile @@ -2,3 +2,4 @@ obj-y := clock.o highbank.o system.o obj-$(CONFIG_DEBUG_HIGHBANK_UART) += lluart.o obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o +obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o diff --git a/arch/arm/mach-highbank/hotplug.c b/arch/arm/mach-highbank/hotplug.c new file mode 100644 index 000000000000..977cebbea580 --- /dev/null +++ b/arch/arm/mach-highbank/hotplug.c @@ -0,0 +1,56 @@ +/* + * Copyright 2011 Calxeda, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ +#include +#include +#include + +#include +#include + +#include "core.h" + +extern void secondary_startup(void); + +int platform_cpu_kill(unsigned int cpu) +{ + return 1; +} + +/* + * platform-specific code to shutdown a CPU + * + */ +void platform_cpu_die(unsigned int cpu) +{ + flush_cache_all(); + + highbank_set_cpu_jump(cpu, secondary_startup); + scu_power_mode(scu_base_addr, SCU_PM_POWEROFF); + + cpu_do_idle(); + + /* We should never return from idle */ + panic("highbank: cpu %d unexpectedly exit from shutdown\n", cpu); +} + +int platform_cpu_disable(unsigned int cpu) +{ + /* + * CPU0 should not be shut down via hotplug. cpu_idle can WFI + * or a proper shutdown or hibernate should be used. + */ + return cpu == 0 ? -EPERM : 0; +} -- cgit v1.2.3 From 8b61f37440388ebbd2a894178fe098f2e70ab392 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Sun, 15 May 2011 12:44:17 -0500 Subject: ARM: highbank: add suspend support Add the platform suspend ops for highbank. Signed-off-by: Rob Herring Reviewed-by: Jamie Iles Reviewed-by: Shawn Guo --- arch/arm/mach-highbank/Makefile | 1 + arch/arm/mach-highbank/pm.c | 55 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 arch/arm/mach-highbank/pm.c (limited to 'arch') diff --git a/arch/arm/mach-highbank/Makefile b/arch/arm/mach-highbank/Makefile index c45078f820ae..986958a5a720 100644 --- a/arch/arm/mach-highbank/Makefile +++ b/arch/arm/mach-highbank/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_DEBUG_HIGHBANK_UART) += lluart.o obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o +obj-$(CONFIG_PM_SLEEP) += pm.o diff --git a/arch/arm/mach-highbank/pm.c b/arch/arm/mach-highbank/pm.c new file mode 100644 index 000000000000..33b3beb89982 --- /dev/null +++ b/arch/arm/mach-highbank/pm.c @@ -0,0 +1,55 @@ +/* + * Copyright 2011 Calxeda, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ + +#include +#include +#include + +#include +#include +#include + +#include "core.h" +#include "sysregs.h" + +static int highbank_suspend_finish(unsigned long val) +{ + cpu_do_idle(); + return 0; +} + +static int highbank_pm_enter(suspend_state_t state) +{ + hignbank_set_pwr_suspend(); + highbank_set_cpu_jump(0, cpu_resume); + + scu_power_mode(scu_base_addr, SCU_PM_POWEROFF); + cpu_suspend(0, highbank_suspend_finish); + + return 0; +} + +static const struct platform_suspend_ops highbank_pm_ops = { + .enter = highbank_pm_enter, + .valid = suspend_valid_only_mem, +}; + +static int __init highbank_pm_init(void) +{ + suspend_set_ops(&highbank_pm_ops); + return 0; +} +module_init(highbank_pm_init); -- cgit v1.2.3 From 7d740f87fd0741c00231a4b13074660d526d5630 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 6 Sep 2011 13:53:26 +0800 Subject: arm/imx6q: add device tree source It adds device tree source and documentation for imx6q platform. Signed-off-by: Shawn Guo --- Documentation/devicetree/bindings/arm/fsl.txt | 6 + arch/arm/boot/dts/imx6q-sabreauto.dts | 62 +++ arch/arm/boot/dts/imx6q.dtsi | 575 ++++++++++++++++++++++++++ 3 files changed, 643 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/fsl.txt create mode 100644 arch/arm/boot/dts/imx6q-sabreauto.dts create mode 100644 arch/arm/boot/dts/imx6q.dtsi (limited to 'arch') diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt new file mode 100644 index 000000000000..345bfc036561 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/fsl.txt @@ -0,0 +1,6 @@ +Freescale i.MX Platforms Device Tree Bindings +----------------------------------------------- + +i.MX6 Quad SABRE Automotive Board +Required root node properties: + - compatible = "fsl,imx6q-sabreauto", "fsl,imx6q"; diff --git a/arch/arm/boot/dts/imx6q-sabreauto.dts b/arch/arm/boot/dts/imx6q-sabreauto.dts new file mode 100644 index 000000000000..072974e443f2 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-sabreauto.dts @@ -0,0 +1,62 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +/include/ "imx6q.dtsi" + +/ { + model = "Freescale i.MX6 Quad SABRE Automotive Board"; + compatible = "fsl,imx6q-sabreauto", "fsl,imx6q"; + + chosen { + bootargs = "console=ttymxc0,115200 root=/dev/mmcblk3p3 rootwait"; + }; + + memory { + reg = <0x10000000 0x80000000>; + }; + + soc { + aips-bus@02100000 { /* AIPS2 */ + enet@02188000 { + phy-mode = "rgmii"; + local-mac-address = [00 04 9F 01 1B 61]; + status = "okay"; + }; + + usdhc@02198000 { /* uSDHC3 */ + cd-gpios = <&gpio5 11 0>; /* GPIO6_11 */ + wp-gpios = <&gpio5 14 0>; /* GPIO6_14 */ + status = "okay"; + }; + + usdhc@0219c000 { /* uSDHC4 */ + fsl,card-wired; + status = "okay"; + }; + + uart3: uart@021f0000 { /* UART4 */ + status = "okay"; + }; + }; + }; + + leds { + compatible = "gpio-leds"; + + debug-led { + label = "Heartbeat"; + gpios = <&gpio2 25 0>; /* GPIO3_25 */ + linux,default-trigger = "heartbeat"; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi new file mode 100644 index 000000000000..7dda599558cc --- /dev/null +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -0,0 +1,575 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/include/ "skeleton.dtsi" + +/ { + aliases { + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a9"; + reg = <0>; + next-level-cache = <&L2>; + }; + + cpu@1 { + compatible = "arm,cortex-a9"; + reg = <1>; + next-level-cache = <&L2>; + }; + + cpu@2 { + compatible = "arm,cortex-a9"; + reg = <2>; + next-level-cache = <&L2>; + }; + + cpu@3 { + compatible = "arm,cortex-a9"; + reg = <3>; + next-level-cache = <&L2>; + }; + }; + + intc: interrupt-controller@00a01000 { + compatible = "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + #address-cells = <1>; + #size-cells = <1>; + interrupt-controller; + reg = <0x00a01000 0x1000>, + <0x00a00100 0x100>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <0>; + + ckil { + compatible = "fsl,imx-ckil", "fixed-clock"; + clock-frequency = <32768>; + }; + + ckih1 { + compatible = "fsl,imx-ckih1", "fixed-clock"; + clock-frequency = <0>; + }; + + osc { + compatible = "fsl,imx-osc", "fixed-clock"; + clock-frequency = <24000000>; + }; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + interrupt-parent = <&intc>; + ranges; + + timer@00a00600 { + compatible = "arm,smp-twd"; + reg = <0x00a00600 0x100>; + interrupts = <1 13 0xf4>; + }; + + L2: l2-cache@00a02000 { + compatible = "arm,pl310-cache"; + reg = <0x00a02000 0x1000>; + interrupts = <0 92 0x04>; + cache-unified; + cache-level = <2>; + }; + + aips-bus@02000000 { /* AIPS1 */ + compatible = "fsl,aips-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x02000000 0x100000>; + ranges; + + spba-bus@02000000 { + compatible = "fsl,spba-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x02000000 0x40000>; + ranges; + + spdif@02004000 { + reg = <0x02004000 0x4000>; + interrupts = <0 52 0x04>; + }; + + ecspi@02008000 { /* eCSPI1 */ + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; + reg = <0x02008000 0x4000>; + interrupts = <0 31 0x04>; + status = "disabled"; + }; + + ecspi@0200c000 { /* eCSPI2 */ + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; + reg = <0x0200c000 0x4000>; + interrupts = <0 32 0x04>; + status = "disabled"; + }; + + ecspi@02010000 { /* eCSPI3 */ + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; + reg = <0x02010000 0x4000>; + interrupts = <0 33 0x04>; + status = "disabled"; + }; + + ecspi@02014000 { /* eCSPI4 */ + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; + reg = <0x02014000 0x4000>; + interrupts = <0 34 0x04>; + status = "disabled"; + }; + + ecspi@02018000 { /* eCSPI5 */ + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; + reg = <0x02018000 0x4000>; + interrupts = <0 35 0x04>; + status = "disabled"; + }; + + uart0: uart@02020000 { /* UART1 */ + compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x02020000 0x4000>; + interrupts = <0 26 0x04>; + status = "disabled"; + }; + + esai@02024000 { + reg = <0x02024000 0x4000>; + interrupts = <0 51 0x04>; + }; + + ssi@02028000 { /* SSI1 */ + reg = <0x02028000 0x4000>; + interrupts = <0 46 0x04>; + }; + + ssi@0202c000 { /* SSI2 */ + reg = <0x0202c000 0x4000>; + interrupts = <0 47 0x04>; + }; + + ssi@02030000 { /* SSI3 */ + reg = <0x02030000 0x4000>; + interrupts = <0 48 0x04>; + }; + + asrc@02034000 { + reg = <0x02034000 0x4000>; + interrupts = <0 50 0x04>; + }; + + spba@0203c000 { + reg = <0x0203c000 0x4000>; + }; + }; + + vpu@02040000 { + reg = <0x02040000 0x3c000>; + interrupts = <0 3 0x04 0 12 0x04>; + }; + + aipstz@0207c000 { /* AIPSTZ1 */ + reg = <0x0207c000 0x4000>; + }; + + pwm@02080000 { /* PWM1 */ + reg = <0x02080000 0x4000>; + interrupts = <0 83 0x04>; + }; + + pwm@02084000 { /* PWM2 */ + reg = <0x02084000 0x4000>; + interrupts = <0 84 0x04>; + }; + + pwm@02088000 { /* PWM3 */ + reg = <0x02088000 0x4000>; + interrupts = <0 85 0x04>; + }; + + pwm@0208c000 { /* PWM4 */ + reg = <0x0208c000 0x4000>; + interrupts = <0 86 0x04>; + }; + + flexcan@02090000 { /* CAN1 */ + reg = <0x02090000 0x4000>; + interrupts = <0 110 0x04>; + }; + + flexcan@02094000 { /* CAN2 */ + reg = <0x02094000 0x4000>; + interrupts = <0 111 0x04>; + }; + + gpt@02098000 { + compatible = "fsl,imx6q-gpt"; + reg = <0x02098000 0x4000>; + interrupts = <0 55 0x04>; + }; + + gpio0: gpio@0209c000 { /* GPIO1 */ + compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio"; + reg = <0x0209c000 0x4000>; + interrupts = <0 66 0x04 0 67 0x04>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio1: gpio@020a0000 { /* GPIO2 */ + compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio"; + reg = <0x020a0000 0x4000>; + interrupts = <0 68 0x04 0 69 0x04>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio2: gpio@020a4000 { /* GPIO3 */ + compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio"; + reg = <0x020a4000 0x4000>; + interrupts = <0 70 0x04 0 71 0x04>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio3: gpio@020a8000 { /* GPIO4 */ + compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio"; + reg = <0x020a8000 0x4000>; + interrupts = <0 72 0x04 0 73 0x04>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio4: gpio@020ac000 { /* GPIO5 */ + compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio"; + reg = <0x020ac000 0x4000>; + interrupts = <0 74 0x04 0 75 0x04>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio5: gpio@020b0000 { /* GPIO6 */ + compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio"; + reg = <0x020b0000 0x4000>; + interrupts = <0 76 0x04 0 77 0x04>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio6: gpio@020b4000 { /* GPIO7 */ + compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio"; + reg = <0x020b4000 0x4000>; + interrupts = <0 78 0x04 0 79 0x04>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + kpp@020b8000 { + reg = <0x020b8000 0x4000>; + interrupts = <0 82 0x04>; + }; + + wdog@020bc000 { /* WDOG1 */ + compatible = "fsl,imx6q-wdt", "fsl,imx21-wdt"; + reg = <0x020bc000 0x4000>; + interrupts = <0 80 0x04>; + status = "disabled"; + }; + + wdog@020c0000 { /* WDOG2 */ + compatible = "fsl,imx6q-wdt", "fsl,imx21-wdt"; + reg = <0x020c0000 0x4000>; + interrupts = <0 81 0x04>; + status = "disabled"; + }; + + ccm@020c4000 { + compatible = "fsl,imx6q-ccm"; + reg = <0x020c4000 0x4000>; + interrupts = <0 87 0x04 0 88 0x04>; + }; + + anatop@020c8000 { + compatible = "fsl,imx6q-anatop"; + reg = <0x020c8000 0x1000>; + interrupts = <0 49 0x04 0 54 0x04 0 127 0x04>; + }; + + usbphy@020c9000 { /* USBPHY1 */ + reg = <0x020c9000 0x1000>; + interrupts = <0 44 0x04>; + }; + + usbphy@020ca000 { /* USBPHY2 */ + reg = <0x020ca000 0x1000>; + interrupts = <0 45 0x04>; + }; + + snvs@020cc000 { + reg = <0x020cc000 0x4000>; + interrupts = <0 19 0x04 0 20 0x04>; + }; + + epit@020d0000 { /* EPIT1 */ + reg = <0x020d0000 0x4000>; + interrupts = <0 56 0x04>; + }; + + epit@020d4000 { /* EPIT2 */ + reg = <0x020d4000 0x4000>; + interrupts = <0 57 0x04>; + }; + + src@020d8000 { + compatible = "fsl,imx6q-src"; + reg = <0x020d8000 0x4000>; + interrupts = <0 91 0x04 0 96 0x04>; + }; + + gpc@020dc000 { + compatible = "fsl,imx6q-gpc"; + reg = <0x020dc000 0x4000>; + interrupts = <0 89 0x04 0 90 0x04>; + }; + + iomuxc@020e0000 { + reg = <0x020e0000 0x4000>; + }; + + dcic@020e4000 { /* DCIC1 */ + reg = <0x020e4000 0x4000>; + interrupts = <0 124 0x04>; + }; + + dcic@020e8000 { /* DCIC2 */ + reg = <0x020e8000 0x4000>; + interrupts = <0 125 0x04>; + }; + + sdma@020ec000 { + compatible = "fsl,imx6q-sdma", "fsl,imx35-sdma"; + reg = <0x020ec000 0x4000>; + interrupts = <0 2 0x04>; + }; + }; + + aips-bus@02100000 { /* AIPS2 */ + compatible = "fsl,aips-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x02100000 0x100000>; + ranges; + + caam@02100000 { + reg = <0x02100000 0x40000>; + interrupts = <0 105 0x04 0 106 0x04>; + }; + + aipstz@0217c000 { /* AIPSTZ2 */ + reg = <0x0217c000 0x4000>; + }; + + enet@02188000 { + compatible = "fsl,imx6q-fec"; + reg = <0x02188000 0x4000>; + interrupts = <0 118 0x04 0 119 0x04>; + status = "disabled"; + }; + + mlb@0218c000 { + reg = <0x0218c000 0x4000>; + interrupts = <0 53 0x04 0 117 0x04 0 126 0x04>; + }; + + usdhc@02190000 { /* uSDHC1 */ + compatible = "fsl,imx6q-usdhc"; + reg = <0x02190000 0x4000>; + interrupts = <0 22 0x04>; + status = "disabled"; + }; + + usdhc@02194000 { /* uSDHC2 */ + compatible = "fsl,imx6q-usdhc"; + reg = <0x02194000 0x4000>; + interrupts = <0 23 0x04>; + status = "disabled"; + }; + + usdhc@02198000 { /* uSDHC3 */ + compatible = "fsl,imx6q-usdhc"; + reg = <0x02198000 0x4000>; + interrupts = <0 24 0x04>; + status = "disabled"; + }; + + usdhc@0219c000 { /* uSDHC4 */ + compatible = "fsl,imx6q-usdhc"; + reg = <0x0219c000 0x4000>; + interrupts = <0 25 0x04>; + status = "disabled"; + }; + + i2c@021a0000 { /* I2C1 */ + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx6q-i2c", "fsl,imx1-i2c"; + reg = <0x021a0000 0x4000>; + interrupts = <0 36 0x04>; + status = "disabled"; + }; + + i2c@021a4000 { /* I2C2 */ + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx6q-i2c", "fsl,imx1-i2c"; + reg = <0x021a4000 0x4000>; + interrupts = <0 37 0x04>; + status = "disabled"; + }; + + i2c@021a8000 { /* I2C3 */ + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx6q-i2c", "fsl,imx1-i2c"; + reg = <0x021a8000 0x4000>; + interrupts = <0 38 0x04>; + status = "disabled"; + }; + + romcp@021ac000 { + reg = <0x021ac000 0x4000>; + }; + + mmdc@021b0000 { /* MMDC0 */ + compatible = "fsl,imx6q-mmdc"; + reg = <0x021b0000 0x4000>; + }; + + mmdc@021b4000 { /* MMDC1 */ + reg = <0x021b4000 0x4000>; + }; + + weim@021b8000 { + reg = <0x021b8000 0x4000>; + interrupts = <0 14 0x04>; + }; + + ocotp@021bc000 { + reg = <0x021bc000 0x4000>; + }; + + ocotp@021c0000 { + reg = <0x021c0000 0x4000>; + interrupts = <0 21 0x04>; + }; + + tzasc@021d0000 { /* TZASC1 */ + reg = <0x021d0000 0x4000>; + interrupts = <0 108 0x04>; + }; + + tzasc@021d4000 { /* TZASC2 */ + reg = <0x021d4000 0x4000>; + interrupts = <0 109 0x04>; + }; + + audmux@021d8000 { + reg = <0x021d8000 0x4000>; + }; + + mipi@021dc000 { /* MIPI-CSI */ + reg = <0x021dc000 0x4000>; + }; + + mipi@021e0000 { /* MIPI-DSI */ + reg = <0x021e0000 0x4000>; + }; + + vdoa@021e4000 { + reg = <0x021e4000 0x4000>; + interrupts = <0 18 0x04>; + }; + + uart1: uart@021e8000 { /* UART2 */ + compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x021e8000 0x4000>; + interrupts = <0 27 0x04>; + status = "disabled"; + }; + + uart2: uart@021ec000 { /* UART3 */ + compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x021ec000 0x4000>; + interrupts = <0 28 0x04>; + status = "disabled"; + }; + + uart3: uart@021f0000 { /* UART4 */ + compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x021f0000 0x4000>; + interrupts = <0 29 0x04>; + status = "disabled"; + }; + + uart4: uart@021f4000 { /* UART5 */ + compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x021f4000 0x4000>; + interrupts = <0 30 0x04>; + status = "disabled"; + }; + }; + }; +}; -- cgit v1.2.3 From bac89d754ba333453576fd38eb6073d7f89818fe Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sun, 2 Oct 2011 15:09:11 +0800 Subject: arm/imx6q: add core definitions and low-level debug uart It adds the core definitions and low-level debug uart support for imx6q. Signed-off-by: Shawn Guo --- arch/arm/Kconfig | 2 +- arch/arm/Kconfig.debug | 7 ++++++ arch/arm/Makefile | 1 + arch/arm/mach-imx/Kconfig | 15 +++++++++++++ arch/arm/mach-imx/Makefile | 2 ++ arch/arm/mach-imx/Makefile.boot | 4 ++++ arch/arm/mach-imx/lluart.c | 32 +++++++++++++++++++++++++++ arch/arm/plat-mxc/Kconfig | 7 ++++++ arch/arm/plat-mxc/include/mach/debug-macro.S | 2 ++ arch/arm/plat-mxc/include/mach/hardware.h | 6 +++++ arch/arm/plat-mxc/include/mach/irqs.h | 10 +++++++-- arch/arm/plat-mxc/include/mach/mx6q.h | 33 ++++++++++++++++++++++++++++ 12 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 arch/arm/mach-imx/lluart.c create mode 100644 arch/arm/plat-mxc/include/mach/mx6q.h (limited to 'arch') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index a94a09ba356b..18400a7b6ca1 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1402,7 +1402,7 @@ config SMP depends on REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP || \ MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4 || \ ARCH_EXYNOS4 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || \ - ARCH_MSM_SCORPIONMP || ARCH_SHMOBILE + ARCH_MSM_SCORPIONMP || ARCH_SHMOBILE || SOC_IMX6Q select USE_GENERIC_SMP_HELPERS select HAVE_ARM_SCU if !ARCH_MSM_SCORPIONMP help diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 13c0631e6e95..a1cb48497312 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -184,6 +184,13 @@ choice Say Y here if you want kernel low-level debugging support on i.MX50 or i.MX53. + config DEBUG_IMX6Q_UART + bool "i.MX6Q Debug UART" + depends on SOC_IMX6Q + help + Say Y here if you want kernel low-level debugging support + on i.MX6Q. + config DEBUG_S3C_UART0 depends on PLAT_SAMSUNG bool "Use S3C UART 0 for low-level debug" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 8904caa736cb..193439eb326f 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -160,6 +160,7 @@ machine-$(CONFIG_ARCH_MV78XX0) := mv78xx0 machine-$(CONFIG_ARCH_IMX_V4_V5) := imx machine-$(CONFIG_ARCH_MX3) := imx machine-$(CONFIG_ARCH_MX5) := mx5 +machine-$(CONFIG_ARCH_MX6) := imx machine-$(CONFIG_ARCH_MXS) := mxs machine-$(CONFIG_ARCH_NETX) := netx machine-$(CONFIG_ARCH_NOMADIK) := nomadik diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index b4e1bf8757c7..cc4b6e46f425 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -592,3 +592,18 @@ config MACH_VPR200 configurations for the board and its peripherals. endif + +if ARCH_MX6 +comment "i.MX6 family:" + +config SOC_IMX6Q + bool "i.MX6 Quad support" + select ARM_GIC + select CACHE_L2X0 + select CPU_V7 + select USE_OF + + help + This enables support for Freescale i.MX6 Quad processor. + +endif diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 116d4b2d2817..b9ed19865a93 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -60,3 +60,5 @@ obj-$(CONFIG_MACH_MX35_3DS) += mach-mx35_3ds.o obj-$(CONFIG_MACH_EUKREA_CPUIMX35) += mach-cpuimx35.o obj-$(CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD) += eukrea_mbimxsd35-baseboard.o obj-$(CONFIG_MACH_VPR200) += mach-vpr200.o + +obj-$(CONFIG_DEBUG_LL) += lluart.o diff --git a/arch/arm/mach-imx/Makefile.boot b/arch/arm/mach-imx/Makefile.boot index ebee18b3884c..136cfc6f2f85 100644 --- a/arch/arm/mach-imx/Makefile.boot +++ b/arch/arm/mach-imx/Makefile.boot @@ -17,3 +17,7 @@ initrd_phys-$(CONFIG_MACH_MX27) := 0xA0800000 zreladdr-$(CONFIG_ARCH_MX3) := 0x80008000 params_phys-$(CONFIG_ARCH_MX3) := 0x80000100 initrd_phys-$(CONFIG_ARCH_MX3) := 0x80800000 + +zreladdr-$(CONFIG_SOC_IMX6Q) += 0x10008000 +params_phys-$(CONFIG_SOC_IMX6Q) := 0x10000100 +initrd_phys-$(CONFIG_SOC_IMX6Q) := 0x10800000 diff --git a/arch/arm/mach-imx/lluart.c b/arch/arm/mach-imx/lluart.c new file mode 100644 index 000000000000..d4ab6f29a766 --- /dev/null +++ b/arch/arm/mach-imx/lluart.c @@ -0,0 +1,32 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include + +static struct map_desc imx_lluart_desc = { +#ifdef CONFIG_DEBUG_IMX6Q_UART + .virtual = MX6Q_IO_P2V(MX6Q_UART4_BASE_ADDR), + .pfn = __phys_to_pfn(MX6Q_UART4_BASE_ADDR), + .length = MX6Q_UART4_SIZE, + .type = MT_DEVICE, +#endif +}; + +void __init imx_lluart_map_io(void) +{ + if (imx_lluart_desc.virtual) + iotable_init(&imx_lluart_desc, 1); +} diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig index 502e45f03178..058d1c5f0043 100644 --- a/arch/arm/plat-mxc/Kconfig +++ b/arch/arm/plat-mxc/Kconfig @@ -29,6 +29,13 @@ config ARCH_MX5 This enables support for machines using Freescale's i.MX50 and i.MX51 processors. +config ARCH_MX6 + bool "i.MX6" + select AUTO_ZRELADDR if !ZBOOT_ROM + select ARM_PATCH_PHYS_VIRT + help + This enables support for systems based on the Freescale i.MX6 family + endchoice source "arch/arm/mach-imx/Kconfig" diff --git a/arch/arm/plat-mxc/include/mach/debug-macro.S b/arch/arm/plat-mxc/include/mach/debug-macro.S index 72986013c1fb..6e192c4a391a 100644 --- a/arch/arm/plat-mxc/include/mach/debug-macro.S +++ b/arch/arm/plat-mxc/include/mach/debug-macro.S @@ -24,6 +24,8 @@ #define UART_PADDR MX51_UART1_BASE_ADDR #elif defined (CONFIG_DEBUG_IMX50_IMX53_UART) #define UART_PADDR MX53_UART1_BASE_ADDR +#elif defined (CONFIG_DEBUG_IMX6Q_UART) +#define UART_PADDR MX6Q_UART4_BASE_ADDR #endif #define UART_VADDR IMX_IO_ADDRESS(UART_PADDR) diff --git a/arch/arm/plat-mxc/include/mach/hardware.h b/arch/arm/plat-mxc/include/mach/hardware.h index eba3118adfbb..a599f01f8b92 100644 --- a/arch/arm/plat-mxc/include/mach/hardware.h +++ b/arch/arm/plat-mxc/include/mach/hardware.h @@ -91,6 +91,11 @@ * SPBA0 0x50000000+0x100000 -> 0xf5400000+0x100000 * AIPS1 0x53f00000+0x100000 -> 0xf5700000+0x100000 * AIPS2 0x63f00000+0x100000 -> 0xf5300000+0x100000 + * mx6q: + * SCU 0x00a00000+0x001000 -> 0xf4000000+0x001000 + * CCM 0x020c4000+0x004000 -> 0xf42c4000+0x004000 + * ANATOP 0x020c8000+0x001000 -> 0xf42c8000+0x001000 + * UART4 0x021f0000+0x004000 -> 0xf42f0000+0x004000 */ #define IMX_IO_P2V(x) ( \ 0xf4000000 + \ @@ -102,6 +107,7 @@ #include +#include #include #include #include diff --git a/arch/arm/plat-mxc/include/mach/irqs.h b/arch/arm/plat-mxc/include/mach/irqs.h index 00e812bbd81d..fd9efb044656 100644 --- a/arch/arm/plat-mxc/include/mach/irqs.h +++ b/arch/arm/plat-mxc/include/mach/irqs.h @@ -14,9 +14,15 @@ #include /* - * SoCs with TZIC interrupt controller have 128 IRQs, those with AVIC have 64 + * SoCs with GIC interrupt controller have 160 IRQs, those with TZIC + * have 128 IRQs, and those with AVIC have 64. + * + * To support single image, the biggest number should be defined on + * top of the list. */ -#ifdef CONFIG_MXC_TZIC +#if defined CONFIG_ARM_GIC +#define MXC_INTERNAL_IRQS 160 +#elif defined CONFIG_MXC_TZIC #define MXC_INTERNAL_IRQS 128 #else #define MXC_INTERNAL_IRQS 64 diff --git a/arch/arm/plat-mxc/include/mach/mx6q.h b/arch/arm/plat-mxc/include/mach/mx6q.h new file mode 100644 index 000000000000..254a561a2799 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/mx6q.h @@ -0,0 +1,33 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef __MACH_MX6Q_H__ +#define __MACH_MX6Q_H__ + +#define MX6Q_IO_P2V(x) IMX_IO_P2V(x) +#define MX6Q_IO_ADDRESS(x) IOMEM(MX6Q_IO_P2V(x)) + +/* + * The following are the blocks that need to be statically mapped. + * For other blocks, the base address really should be retrieved from + * device tree. + */ +#define MX6Q_SCU_BASE_ADDR 0x00a00000 +#define MX6Q_SCU_SIZE 0x1000 +#define MX6Q_CCM_BASE_ADDR 0x020c4000 +#define MX6Q_CCM_SIZE 0x4000 +#define MX6Q_ANATOP_BASE_ADDR 0x020c8000 +#define MX6Q_ANATOP_SIZE 0x1000 +#define MX6Q_UART4_BASE_ADDR 0x021f0000 +#define MX6Q_UART4_SIZE 0x4000 + +#endif /* __MACH_MX6Q_H__ */ -- cgit v1.2.3 From 1103643c266ae45c7098e0f7f3ee0b68e3e7c7cc Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 24 Sep 2011 00:43:06 +0800 Subject: arm/imx: add gic_handle_irq function This is a plain translation of assembly gic irq handler to C function for CONFIG_MULTI_IRQ_HANDLER support on imx family. Signed-off-by: Shawn Guo --- arch/arm/plat-mxc/Makefile | 2 +- arch/arm/plat-mxc/gic.c | 48 ++++++++++++++++++++++++++++ arch/arm/plat-mxc/include/mach/common.h | 2 ++ arch/arm/plat-mxc/include/mach/entry-macro.S | 6 ++++ 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 arch/arm/plat-mxc/gic.c (limited to 'arch') diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile index d53c35fe2ea7..b9f0f5f499a4 100644 --- a/arch/arm/plat-mxc/Makefile +++ b/arch/arm/plat-mxc/Makefile @@ -5,7 +5,7 @@ # Common support obj-y := clock.o time.o devices.o cpu.o system.o irq-common.o -# MX51 uses the TZIC interrupt controller, older platforms use AVIC +obj-$(CONFIG_ARM_GIC) += gic.o obj-$(CONFIG_MXC_TZIC) += tzic.o obj-$(CONFIG_MXC_AVIC) += avic.o diff --git a/arch/arm/plat-mxc/gic.c b/arch/arm/plat-mxc/gic.c new file mode 100644 index 000000000000..b3b8eed263b8 --- /dev/null +++ b/arch/arm/plat-mxc/gic.c @@ -0,0 +1,48 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#ifdef CONFIG_SMP +#include +#endif + +asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) +{ + u32 irqstat, irqnr; + + do { + irqstat = readl_relaxed(gic_cpu_base_addr + GIC_CPU_INTACK); + irqnr = irqstat & 0x3ff; + if (irqnr == 1023) + break; + + if (irqnr > 29 && irqnr < 1021) + handle_IRQ(irqnr, regs); +#ifdef CONFIG_SMP + else if (irqnr < 16) { + writel_relaxed(irqstat, gic_cpu_base_addr + + GIC_CPU_EOI); + handle_IPI(irqnr, regs); + } +#endif +#ifdef CONFIG_LOCAL_TIMERS + else if (irqnr == 29) { + writel_relaxed(irqstat, gic_cpu_base_addr + + GIC_CPU_EOI); + handle_local_timer(regs); + } +#endif + } while (1); +} diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h index ace4bb550edc..c2258374488a 100644 --- a/arch/arm/plat-mxc/include/mach/common.h +++ b/arch/arm/plat-mxc/include/mach/common.h @@ -86,6 +86,7 @@ extern void imx_print_silicon_rev(const char *cpu, int srev); void avic_handle_irq(struct pt_regs *); void tzic_handle_irq(struct pt_regs *); +void gic_handle_irq(struct pt_regs *); #define imx1_handle_irq avic_handle_irq #define imx21_handle_irq avic_handle_irq @@ -96,5 +97,6 @@ void tzic_handle_irq(struct pt_regs *); #define imx50_handle_irq tzic_handle_irq #define imx51_handle_irq tzic_handle_irq #define imx53_handle_irq tzic_handle_irq +#define imx6q_handle_irq gic_handle_irq #endif diff --git a/arch/arm/plat-mxc/include/mach/entry-macro.S b/arch/arm/plat-mxc/include/mach/entry-macro.S index 842fbcb0d6cc..9fe0dfcf4e7e 100644 --- a/arch/arm/plat-mxc/include/mach/entry-macro.S +++ b/arch/arm/plat-mxc/include/mach/entry-macro.S @@ -22,3 +22,9 @@ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp .endm + + .macro test_for_ipi, irqnr, irqstat, base, tmp + .endm + + .macro test_for_ltirq, irqnr, irqstat, base, tmp + .endm -- cgit v1.2.3 From 9fbbe6890c88aa332efe61d5894108dd8b932530 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 6 Sep 2011 14:39:44 +0800 Subject: arm/imx6q: add core drivers clock, gpc, mmdc and src It adds a number of core drivers support for imx6q, including clock, General Power Controller (gpc), Multi Mode DDR Controller(mmdc) and System Reset Controller (src). Signed-off-by: Ranjani Vaidyanathan Signed-off-by: Shawn Guo --- arch/arm/mach-imx/Kconfig | 13 + arch/arm/mach-imx/Makefile | 4 + arch/arm/mach-imx/clock-imx6q.c | 2012 +++++++++++++++++++++++++++++++++++++++ arch/arm/mach-imx/gpc.c | 113 +++ arch/arm/mach-imx/mmdc.c | 72 ++ arch/arm/mach-imx/src.c | 49 + 6 files changed, 2263 insertions(+) create mode 100644 arch/arm/mach-imx/clock-imx6q.c create mode 100644 arch/arm/mach-imx/gpc.c create mode 100644 arch/arm/mach-imx/mmdc.c create mode 100644 arch/arm/mach-imx/src.c (limited to 'arch') diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index cc4b6e46f425..40372a8e301b 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -1,5 +1,15 @@ config IMX_HAVE_DMA_V1 bool + +config HAVE_IMX_GPC + bool + +config HAVE_IMX_MMDC + bool + +config HAVE_IMX_SRC + bool + # # ARCH_MX31 and ARCH_MX35 are left for compatibility # Some usages assume that having one of them implies not having (e.g.) ARCH_MX2. @@ -601,6 +611,9 @@ config SOC_IMX6Q select ARM_GIC select CACHE_L2X0 select CPU_V7 + select HAVE_IMX_GPC + select HAVE_IMX_MMDC + select HAVE_IMX_SRC select USE_OF help diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index b9ed19865a93..65218d98a78d 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -62,3 +62,7 @@ obj-$(CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD) += eukrea_mbimxsd35-baseboard.o obj-$(CONFIG_MACH_VPR200) += mach-vpr200.o obj-$(CONFIG_DEBUG_LL) += lluart.o +obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o +obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o +obj-$(CONFIG_HAVE_IMX_SRC) += src.o +obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o diff --git a/arch/arm/mach-imx/clock-imx6q.c b/arch/arm/mach-imx/clock-imx6q.c new file mode 100644 index 000000000000..e0b926dfeced --- /dev/null +++ b/arch/arm/mach-imx/clock-imx6q.c @@ -0,0 +1,2012 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PLL_BASE IMX_IO_ADDRESS(MX6Q_ANATOP_BASE_ADDR) +#define PLL1_SYS (PLL_BASE + 0x000) +#define PLL2_BUS (PLL_BASE + 0x030) +#define PLL3_USB_OTG (PLL_BASE + 0x010) +#define PLL4_AUDIO (PLL_BASE + 0x070) +#define PLL5_VIDEO (PLL_BASE + 0x0a0) +#define PLL6_MLB (PLL_BASE + 0x0d0) +#define PLL7_USB_HOST (PLL_BASE + 0x020) +#define PLL8_ENET (PLL_BASE + 0x0e0) +#define PFD_480 (PLL_BASE + 0x0f0) +#define PFD_528 (PLL_BASE + 0x100) +#define PLL_NUM_OFFSET 0x010 +#define PLL_DENOM_OFFSET 0x020 + +#define PFD0 7 +#define PFD1 15 +#define PFD2 23 +#define PFD3 31 +#define PFD_FRAC_MASK 0x3f + +#define BM_PLL_BYPASS (0x1 << 16) +#define BM_PLL_ENABLE (0x1 << 13) +#define BM_PLL_POWER_DOWN (0x1 << 12) +#define BM_PLL_LOCK (0x1 << 31) +#define BP_PLL_SYS_DIV_SELECT 0 +#define BM_PLL_SYS_DIV_SELECT (0x7f << 0) +#define BP_PLL_BUS_DIV_SELECT 0 +#define BM_PLL_BUS_DIV_SELECT (0x1 << 0) +#define BP_PLL_USB_DIV_SELECT 0 +#define BM_PLL_USB_DIV_SELECT (0x3 << 0) +#define BP_PLL_AV_DIV_SELECT 0 +#define BM_PLL_AV_DIV_SELECT (0x7f << 0) +#define BP_PLL_ENET_DIV_SELECT 0 +#define BM_PLL_ENET_DIV_SELECT (0x3 << 0) +#define BM_PLL_ENET_EN_PCIE (0x1 << 19) +#define BM_PLL_ENET_EN_SATA (0x1 << 20) + +#define CCM_BASE IMX_IO_ADDRESS(MX6Q_CCM_BASE_ADDR) +#define CCR (CCM_BASE + 0x00) +#define CCDR (CCM_BASE + 0x04) +#define CSR (CCM_BASE + 0x08) +#define CCSR (CCM_BASE + 0x0c) +#define CACRR (CCM_BASE + 0x10) +#define CBCDR (CCM_BASE + 0x14) +#define CBCMR (CCM_BASE + 0x18) +#define CSCMR1 (CCM_BASE + 0x1c) +#define CSCMR2 (CCM_BASE + 0x20) +#define CSCDR1 (CCM_BASE + 0x24) +#define CS1CDR (CCM_BASE + 0x28) +#define CS2CDR (CCM_BASE + 0x2c) +#define CDCDR (CCM_BASE + 0x30) +#define CHSCCDR (CCM_BASE + 0x34) +#define CSCDR2 (CCM_BASE + 0x38) +#define CSCDR3 (CCM_BASE + 0x3c) +#define CSCDR4 (CCM_BASE + 0x40) +#define CWDR (CCM_BASE + 0x44) +#define CDHIPR (CCM_BASE + 0x48) +#define CDCR (CCM_BASE + 0x4c) +#define CTOR (CCM_BASE + 0x50) +#define CLPCR (CCM_BASE + 0x54) +#define CISR (CCM_BASE + 0x58) +#define CIMR (CCM_BASE + 0x5c) +#define CCOSR (CCM_BASE + 0x60) +#define CGPR (CCM_BASE + 0x64) +#define CCGR0 (CCM_BASE + 0x68) +#define CCGR1 (CCM_BASE + 0x6c) +#define CCGR2 (CCM_BASE + 0x70) +#define CCGR3 (CCM_BASE + 0x74) +#define CCGR4 (CCM_BASE + 0x78) +#define CCGR5 (CCM_BASE + 0x7c) +#define CCGR6 (CCM_BASE + 0x80) +#define CCGR7 (CCM_BASE + 0x84) +#define CMEOR (CCM_BASE + 0x88) + +#define CG0 0 +#define CG1 2 +#define CG2 4 +#define CG3 6 +#define CG4 8 +#define CG5 10 +#define CG6 12 +#define CG7 14 +#define CG8 16 +#define CG9 18 +#define CG10 20 +#define CG11 22 +#define CG12 24 +#define CG13 26 +#define CG14 28 +#define CG15 30 + +#define BM_CCSR_PLL1_SW_SEL (0x1 << 2) +#define BM_CCSR_STEP_SEL (0x1 << 8) + +#define BP_CACRR_ARM_PODF 0 +#define BM_CACRR_ARM_PODF (0x7 << 0) + +#define BP_CBCDR_PERIPH2_CLK2_PODF 0 +#define BM_CBCDR_PERIPH2_CLK2_PODF (0x7 << 0) +#define BP_CBCDR_MMDC_CH1_AXI_PODF 3 +#define BM_CBCDR_MMDC_CH1_AXI_PODF (0x7 << 3) +#define BP_CBCDR_AXI_SEL 6 +#define BM_CBCDR_AXI_SEL (0x3 << 6) +#define BP_CBCDR_IPG_PODF 8 +#define BM_CBCDR_IPG_PODF (0x3 << 8) +#define BP_CBCDR_AHB_PODF 10 +#define BM_CBCDR_AHB_PODF (0x7 << 10) +#define BP_CBCDR_AXI_PODF 16 +#define BM_CBCDR_AXI_PODF (0x7 << 16) +#define BP_CBCDR_MMDC_CH0_AXI_PODF 19 +#define BM_CBCDR_MMDC_CH0_AXI_PODF (0x7 << 19) +#define BP_CBCDR_PERIPH_CLK_SEL 25 +#define BM_CBCDR_PERIPH_CLK_SEL (0x1 << 25) +#define BP_CBCDR_PERIPH2_CLK_SEL 26 +#define BM_CBCDR_PERIPH2_CLK_SEL (0x1 << 26) +#define BP_CBCDR_PERIPH_CLK2_PODF 27 +#define BM_CBCDR_PERIPH_CLK2_PODF (0x7 << 27) + +#define BP_CBCMR_GPU2D_AXI_SEL 0 +#define BM_CBCMR_GPU2D_AXI_SEL (0x1 << 0) +#define BP_CBCMR_GPU3D_AXI_SEL 1 +#define BM_CBCMR_GPU3D_AXI_SEL (0x1 << 1) +#define BP_CBCMR_GPU3D_CORE_SEL 4 +#define BM_CBCMR_GPU3D_CORE_SEL (0x3 << 4) +#define BP_CBCMR_GPU3D_SHADER_SEL 8 +#define BM_CBCMR_GPU3D_SHADER_SEL (0x3 << 8) +#define BP_CBCMR_PCIE_AXI_SEL 10 +#define BM_CBCMR_PCIE_AXI_SEL (0x1 << 10) +#define BP_CBCMR_VDO_AXI_SEL 11 +#define BM_CBCMR_VDO_AXI_SEL (0x1 << 11) +#define BP_CBCMR_PERIPH_CLK2_SEL 12 +#define BM_CBCMR_PERIPH_CLK2_SEL (0x3 << 12) +#define BP_CBCMR_VPU_AXI_SEL 14 +#define BM_CBCMR_VPU_AXI_SEL (0x3 << 14) +#define BP_CBCMR_GPU2D_CORE_SEL 16 +#define BM_CBCMR_GPU2D_CORE_SEL (0x3 << 16) +#define BP_CBCMR_PRE_PERIPH_CLK_SEL 18 +#define BM_CBCMR_PRE_PERIPH_CLK_SEL (0x3 << 18) +#define BP_CBCMR_PERIPH2_CLK2_SEL 20 +#define BM_CBCMR_PERIPH2_CLK2_SEL (0x1 << 20) +#define BP_CBCMR_PRE_PERIPH2_CLK_SEL 21 +#define BM_CBCMR_PRE_PERIPH2_CLK_SEL (0x3 << 21) +#define BP_CBCMR_GPU2D_CORE_PODF 23 +#define BM_CBCMR_GPU2D_CORE_PODF (0x7 << 23) +#define BP_CBCMR_GPU3D_CORE_PODF 26 +#define BM_CBCMR_GPU3D_CORE_PODF (0x7 << 26) +#define BP_CBCMR_GPU3D_SHADER_PODF 29 +#define BM_CBCMR_GPU3D_SHADER_PODF (0x7 << 29) + +#define BP_CSCMR1_PERCLK_PODF 0 +#define BM_CSCMR1_PERCLK_PODF (0x3f << 0) +#define BP_CSCMR1_SSI1_SEL 10 +#define BM_CSCMR1_SSI1_SEL (0x3 << 10) +#define BP_CSCMR1_SSI2_SEL 12 +#define BM_CSCMR1_SSI2_SEL (0x3 << 12) +#define BP_CSCMR1_SSI3_SEL 14 +#define BM_CSCMR1_SSI3_SEL (0x3 << 14) +#define BP_CSCMR1_USDHC1_SEL 16 +#define BM_CSCMR1_USDHC1_SEL (0x1 << 16) +#define BP_CSCMR1_USDHC2_SEL 17 +#define BM_CSCMR1_USDHC2_SEL (0x1 << 17) +#define BP_CSCMR1_USDHC3_SEL 18 +#define BM_CSCMR1_USDHC3_SEL (0x1 << 18) +#define BP_CSCMR1_USDHC4_SEL 19 +#define BM_CSCMR1_USDHC4_SEL (0x1 << 19) +#define BP_CSCMR1_EMI_PODF 20 +#define BM_CSCMR1_EMI_PODF (0x7 << 20) +#define BP_CSCMR1_EMI_SLOW_PODF 23 +#define BM_CSCMR1_EMI_SLOW_PODF (0x7 << 23) +#define BP_CSCMR1_EMI_SEL 27 +#define BM_CSCMR1_EMI_SEL (0x3 << 27) +#define BP_CSCMR1_EMI_SLOW_SEL 29 +#define BM_CSCMR1_EMI_SLOW_SEL (0x3 << 29) + +#define BP_CSCMR2_CAN_PODF 2 +#define BM_CSCMR2_CAN_PODF (0x3f << 2) +#define BM_CSCMR2_LDB_DI0_IPU_DIV (0x1 << 10) +#define BM_CSCMR2_LDB_DI1_IPU_DIV (0x1 << 11) +#define BP_CSCMR2_ESAI_SEL 19 +#define BM_CSCMR2_ESAI_SEL (0x3 << 19) + +#define BP_CSCDR1_UART_PODF 0 +#define BM_CSCDR1_UART_PODF (0x3f << 0) +#define BP_CSCDR1_USDHC1_PODF 11 +#define BM_CSCDR1_USDHC1_PODF (0x7 << 11) +#define BP_CSCDR1_USDHC2_PODF 16 +#define BM_CSCDR1_USDHC2_PODF (0x7 << 16) +#define BP_CSCDR1_USDHC3_PODF 19 +#define BM_CSCDR1_USDHC3_PODF (0x7 << 19) +#define BP_CSCDR1_USDHC4_PODF 22 +#define BM_CSCDR1_USDHC4_PODF (0x7 << 22) +#define BP_CSCDR1_VPU_AXI_PODF 25 +#define BM_CSCDR1_VPU_AXI_PODF (0x7 << 25) + +#define BP_CS1CDR_SSI1_PODF 0 +#define BM_CS1CDR_SSI1_PODF (0x3f << 0) +#define BP_CS1CDR_SSI1_PRED 6 +#define BM_CS1CDR_SSI1_PRED (0x7 << 6) +#define BP_CS1CDR_ESAI_PRED 9 +#define BM_CS1CDR_ESAI_PRED (0x7 << 9) +#define BP_CS1CDR_SSI3_PODF 16 +#define BM_CS1CDR_SSI3_PODF (0x3f << 16) +#define BP_CS1CDR_SSI3_PRED 22 +#define BM_CS1CDR_SSI3_PRED (0x7 << 22) +#define BP_CS1CDR_ESAI_PODF 25 +#define BM_CS1CDR_ESAI_PODF (0x7 << 25) + +#define BP_CS2CDR_SSI2_PODF 0 +#define BM_CS2CDR_SSI2_PODF (0x3f << 0) +#define BP_CS2CDR_SSI2_PRED 6 +#define BM_CS2CDR_SSI2_PRED (0x7 << 6) +#define BP_CS2CDR_LDB_DI0_SEL 9 +#define BM_CS2CDR_LDB_DI0_SEL (0x7 << 9) +#define BP_CS2CDR_LDB_DI1_SEL 12 +#define BM_CS2CDR_LDB_DI1_SEL (0x7 << 12) +#define BP_CS2CDR_ENFC_SEL 16 +#define BM_CS2CDR_ENFC_SEL (0x3 << 16) +#define BP_CS2CDR_ENFC_PRED 18 +#define BM_CS2CDR_ENFC_PRED (0x7 << 18) +#define BP_CS2CDR_ENFC_PODF 21 +#define BM_CS2CDR_ENFC_PODF (0x3f << 21) + +#define BP_CDCDR_ASRC_SERIAL_SEL 7 +#define BM_CDCDR_ASRC_SERIAL_SEL (0x3 << 7) +#define BP_CDCDR_ASRC_SERIAL_PODF 9 +#define BM_CDCDR_ASRC_SERIAL_PODF (0x7 << 9) +#define BP_CDCDR_ASRC_SERIAL_PRED 12 +#define BM_CDCDR_ASRC_SERIAL_PRED (0x7 << 12) +#define BP_CDCDR_SPDIF_SEL 20 +#define BM_CDCDR_SPDIF_SEL (0x3 << 20) +#define BP_CDCDR_SPDIF_PODF 22 +#define BM_CDCDR_SPDIF_PODF (0x7 << 22) +#define BP_CDCDR_SPDIF_PRED 25 +#define BM_CDCDR_SPDIF_PRED (0x7 << 25) +#define BP_CDCDR_HSI_TX_PODF 29 +#define BM_CDCDR_HSI_TX_PODF (0x7 << 29) +#define BP_CDCDR_HSI_TX_SEL 28 +#define BM_CDCDR_HSI_TX_SEL (0x1 << 28) + +#define BP_CHSCCDR_IPU1_DI0_SEL 0 +#define BM_CHSCCDR_IPU1_DI0_SEL (0x7 << 0) +#define BP_CHSCCDR_IPU1_DI0_PRE_PODF 3 +#define BM_CHSCCDR_IPU1_DI0_PRE_PODF (0x7 << 3) +#define BP_CHSCCDR_IPU1_DI0_PRE_SEL 6 +#define BM_CHSCCDR_IPU1_DI0_PRE_SEL (0x7 << 6) +#define BP_CHSCCDR_IPU1_DI1_SEL 9 +#define BM_CHSCCDR_IPU1_DI1_SEL (0x7 << 9) +#define BP_CHSCCDR_IPU1_DI1_PRE_PODF 12 +#define BM_CHSCCDR_IPU1_DI1_PRE_PODF (0x7 << 12) +#define BP_CHSCCDR_IPU1_DI1_PRE_SEL 15 +#define BM_CHSCCDR_IPU1_DI1_PRE_SEL (0x7 << 15) + +#define BP_CSCDR2_IPU2_DI0_SEL 0 +#define BM_CSCDR2_IPU2_DI0_SEL (0x7) +#define BP_CSCDR2_IPU2_DI0_PRE_PODF 3 +#define BM_CSCDR2_IPU2_DI0_PRE_PODF (0x7 << 3) +#define BP_CSCDR2_IPU2_DI0_PRE_SEL 6 +#define BM_CSCDR2_IPU2_DI0_PRE_SEL (0x7 << 6) +#define BP_CSCDR2_IPU2_DI1_SEL 9 +#define BM_CSCDR2_IPU2_DI1_SEL (0x7 << 9) +#define BP_CSCDR2_IPU2_DI1_PRE_PODF 12 +#define BM_CSCDR2_IPU2_DI1_PRE_PODF (0x7 << 12) +#define BP_CSCDR2_IPU2_DI1_PRE_SEL 15 +#define BM_CSCDR2_IPU2_DI1_PRE_SEL (0x7 << 15) +#define BP_CSCDR2_ECSPI_CLK_PODF 19 +#define BM_CSCDR2_ECSPI_CLK_PODF (0x3f << 19) + +#define BP_CSCDR3_IPU1_HSP_SEL 9 +#define BM_CSCDR3_IPU1_HSP_SEL (0x3 << 9) +#define BP_CSCDR3_IPU1_HSP_PODF 11 +#define BM_CSCDR3_IPU1_HSP_PODF (0x7 << 11) +#define BP_CSCDR3_IPU2_HSP_SEL 14 +#define BM_CSCDR3_IPU2_HSP_SEL (0x3 << 14) +#define BP_CSCDR3_IPU2_HSP_PODF 16 +#define BM_CSCDR3_IPU2_HSP_PODF (0x7 << 16) + +#define BM_CDHIPR_AXI_PODF_BUSY (0x1 << 0) +#define BM_CDHIPR_AHB_PODF_BUSY (0x1 << 1) +#define BM_CDHIPR_MMDC_CH1_PODF_BUSY (0x1 << 2) +#define BM_CDHIPR_PERIPH2_SEL_BUSY (0x1 << 3) +#define BM_CDHIPR_MMDC_CH0_PODF_BUSY (0x1 << 4) +#define BM_CDHIPR_PERIPH_SEL_BUSY (0x1 << 5) +#define BM_CDHIPR_ARM_PODF_BUSY (0x1 << 16) + +#define BP_CLPCR_LPM 0 +#define BM_CLPCR_LPM (0x3 << 0) +#define BM_CLPCR_BYPASS_PMIC_READY (0x1 << 2) +#define BM_CLPCR_ARM_CLK_DIS_ON_LPM (0x1 << 5) +#define BM_CLPCR_SBYOS (0x1 << 6) +#define BM_CLPCR_DIS_REF_OSC (0x1 << 7) +#define BM_CLPCR_VSTBY (0x1 << 8) +#define BP_CLPCR_STBY_COUNT 9 +#define BM_CLPCR_STBY_COUNT (0x3 << 9) +#define BM_CLPCR_COSC_PWRDOWN (0x1 << 11) +#define BM_CLPCR_WB_PER_AT_LPM (0x1 << 16) +#define BM_CLPCR_WB_CORE_AT_LPM (0x1 << 17) +#define BM_CLPCR_BYP_MMDC_CH0_LPM_HS (0x1 << 19) +#define BM_CLPCR_BYP_MMDC_CH1_LPM_HS (0x1 << 21) +#define BM_CLPCR_MASK_CORE0_WFI (0x1 << 22) +#define BM_CLPCR_MASK_CORE1_WFI (0x1 << 23) +#define BM_CLPCR_MASK_CORE2_WFI (0x1 << 24) +#define BM_CLPCR_MASK_CORE3_WFI (0x1 << 25) +#define BM_CLPCR_MASK_SCU_IDLE (0x1 << 26) +#define BM_CLPCR_MASK_L2CC_IDLE (0x1 << 27) + +#define FREQ_480M 480000000 +#define FREQ_528M 528000000 +#define FREQ_594M 594000000 +#define FREQ_650M 650000000 +#define FREQ_1300M 1300000000 + +static struct clk pll1_sys; +static struct clk pll2_bus; +static struct clk pll3_usb_otg; +static struct clk pll4_audio; +static struct clk pll5_video; +static struct clk pll6_mlb; +static struct clk pll7_usb_host; +static struct clk pll8_enet; +static struct clk apbh_dma_clk; +static struct clk arm_clk; +static struct clk ipg_clk; +static struct clk ahb_clk; +static struct clk axi_clk; +static struct clk mmdc_ch0_axi_clk; +static struct clk mmdc_ch1_axi_clk; +static struct clk periph_clk; +static struct clk periph_pre_clk; +static struct clk periph_clk2_clk; +static struct clk periph2_clk; +static struct clk periph2_pre_clk; +static struct clk periph2_clk2_clk; +static struct clk gpu2d_core_clk; +static struct clk gpu3d_core_clk; +static struct clk gpu3d_shader_clk; +static struct clk ipg_perclk; +static struct clk emi_clk; +static struct clk emi_slow_clk; +static struct clk can1_clk; +static struct clk uart_clk; +static struct clk usdhc1_clk; +static struct clk usdhc2_clk; +static struct clk usdhc3_clk; +static struct clk usdhc4_clk; +static struct clk vpu_clk; +static struct clk hsi_tx_clk; +static struct clk ipu1_di0_pre_clk; +static struct clk ipu1_di1_pre_clk; +static struct clk ipu2_di0_pre_clk; +static struct clk ipu2_di1_pre_clk; +static struct clk ipu1_clk; +static struct clk ipu2_clk; +static struct clk ssi1_clk; +static struct clk ssi3_clk; +static struct clk esai_clk; +static struct clk ssi2_clk; +static struct clk spdif_clk; +static struct clk asrc_serial_clk; +static struct clk gpu2d_axi_clk; +static struct clk gpu3d_axi_clk; +static struct clk pcie_clk; +static struct clk vdo_axi_clk; +static struct clk ldb_di0_clk; +static struct clk ldb_di1_clk; +static struct clk ipu1_di0_clk; +static struct clk ipu1_di1_clk; +static struct clk ipu2_di0_clk; +static struct clk ipu2_di1_clk; +static struct clk enfc_clk; +static struct clk dummy_clk = {}; + +static unsigned long external_high_reference; +static unsigned long external_low_reference; +static unsigned long oscillator_reference; + +static unsigned long get_oscillator_reference_clock_rate(struct clk *clk) +{ + return oscillator_reference; +} + +static unsigned long get_high_reference_clock_rate(struct clk *clk) +{ + return external_high_reference; +} + +static unsigned long get_low_reference_clock_rate(struct clk *clk) +{ + return external_low_reference; +} + +static struct clk ckil_clk = { + .get_rate = get_low_reference_clock_rate, +}; + +static struct clk ckih_clk = { + .get_rate = get_high_reference_clock_rate, +}; + +static struct clk osc_clk = { + .get_rate = get_oscillator_reference_clock_rate, +}; + +static inline void __iomem *pll_get_reg_addr(struct clk *pll) +{ + if (pll == &pll1_sys) + return PLL1_SYS; + else if (pll == &pll2_bus) + return PLL2_BUS; + else if (pll == &pll3_usb_otg) + return PLL3_USB_OTG; + else if (pll == &pll4_audio) + return PLL4_AUDIO; + else if (pll == &pll5_video) + return PLL5_VIDEO; + else if (pll == &pll6_mlb) + return PLL6_MLB; + else if (pll == &pll7_usb_host) + return PLL7_USB_HOST; + else if (pll == &pll8_enet) + return PLL8_ENET; + else + BUG(); + + return NULL; +} + +static int pll_enable(struct clk *clk) +{ + int timeout = 0x100000; + void __iomem *reg; + u32 val; + + reg = pll_get_reg_addr(clk); + val = readl_relaxed(reg); + val &= ~BM_PLL_BYPASS; + val &= ~BM_PLL_POWER_DOWN; + /* 480MHz PLLs have the opposite definition for power bit */ + if (clk == &pll3_usb_otg || clk == &pll7_usb_host) + val |= BM_PLL_POWER_DOWN; + writel_relaxed(val, reg); + + /* Wait for PLL to lock */ + while (!(readl_relaxed(reg) & BM_PLL_LOCK) && --timeout) + cpu_relax(); + + if (unlikely(!timeout)) + return -EBUSY; + + /* Enable the PLL output now */ + val = readl_relaxed(reg); + val |= BM_PLL_ENABLE; + writel_relaxed(val, reg); + + return 0; +} + +static void pll_disable(struct clk *clk) +{ + void __iomem *reg; + u32 val; + + reg = pll_get_reg_addr(clk); + val = readl_relaxed(reg); + val &= ~BM_PLL_ENABLE; + val |= BM_PLL_BYPASS; + val |= BM_PLL_POWER_DOWN; + if (clk == &pll3_usb_otg || clk == &pll7_usb_host) + val &= ~BM_PLL_POWER_DOWN; + writel_relaxed(val, reg); +} + +static unsigned long pll1_sys_get_rate(struct clk *clk) +{ + u32 div = (readl_relaxed(PLL1_SYS) & BM_PLL_SYS_DIV_SELECT) >> + BP_PLL_SYS_DIV_SELECT; + + return clk_get_rate(clk->parent) * div / 2; +} + +static int pll1_sys_set_rate(struct clk *clk, unsigned long rate) +{ + u32 val, div; + + if (rate < FREQ_650M || rate > FREQ_1300M) + return -EINVAL; + + div = rate * 2 / clk_get_rate(clk->parent); + val = readl_relaxed(PLL1_SYS); + val &= ~BM_PLL_SYS_DIV_SELECT; + val |= div << BP_PLL_SYS_DIV_SELECT; + writel_relaxed(val, PLL1_SYS); + + return 0; +} + +static unsigned long pll8_enet_get_rate(struct clk *clk) +{ + u32 div = (readl_relaxed(PLL8_ENET) & BM_PLL_ENET_DIV_SELECT) >> + BP_PLL_ENET_DIV_SELECT; + + switch (div) { + case 0: + return 25000000; + case 1: + return 50000000; + case 2: + return 100000000; + case 3: + return 125000000; + } + + return 0; +} + +static int pll8_enet_set_rate(struct clk *clk, unsigned long rate) +{ + u32 val, div; + + switch (rate) { + case 25000000: + div = 0; + break; + case 50000000: + div = 1; + break; + case 100000000: + div = 2; + break; + case 125000000: + div = 3; + break; + default: + return -EINVAL; + } + + val = readl_relaxed(PLL8_ENET); + val &= ~BM_PLL_ENET_DIV_SELECT; + val |= div << BP_PLL_ENET_DIV_SELECT; + writel_relaxed(val, PLL8_ENET); + + return 0; +} + +static unsigned long pll_av_get_rate(struct clk *clk) +{ + void __iomem *reg = (clk == &pll4_audio) ? PLL4_AUDIO : PLL5_VIDEO; + unsigned long parent_rate = clk_get_rate(clk->parent); + u32 mfn = readl_relaxed(reg + PLL_NUM_OFFSET); + u32 mfd = readl_relaxed(reg + PLL_DENOM_OFFSET); + u32 div = (readl_relaxed(reg) & BM_PLL_AV_DIV_SELECT) >> + BP_PLL_AV_DIV_SELECT; + + return (parent_rate * div) + ((parent_rate / mfd) * mfn); +} + +static int pll_av_set_rate(struct clk *clk, unsigned long rate) +{ + void __iomem *reg = (clk == &pll4_audio) ? PLL4_AUDIO : PLL5_VIDEO; + unsigned int parent_rate = clk_get_rate(clk->parent); + u32 val, div; + u32 mfn, mfd = 1000000; + s64 temp64; + + if (rate < FREQ_650M || rate > FREQ_1300M) + return -EINVAL; + + div = rate / parent_rate; + temp64 = (u64) (rate - div * parent_rate); + temp64 *= mfd; + do_div(temp64, parent_rate); + mfn = temp64; + + val = readl_relaxed(reg); + val &= ~BM_PLL_AV_DIV_SELECT; + val |= div << BP_PLL_AV_DIV_SELECT; + writel_relaxed(val, reg); + writel_relaxed(mfn, reg + PLL_NUM_OFFSET); + writel_relaxed(mfd, reg + PLL_DENOM_OFFSET); + + return 0; +} + +static void __iomem *pll_get_div_reg_bit(struct clk *clk, u32 *bp, u32 *bm) +{ + void __iomem *reg; + + if (clk == &pll2_bus) { + reg = PLL2_BUS; + *bp = BP_PLL_BUS_DIV_SELECT; + *bm = BM_PLL_BUS_DIV_SELECT; + } else if (clk == &pll3_usb_otg) { + reg = PLL3_USB_OTG; + *bp = BP_PLL_USB_DIV_SELECT; + *bm = BM_PLL_USB_DIV_SELECT; + } else if (clk == &pll7_usb_host) { + reg = PLL7_USB_HOST; + *bp = BP_PLL_USB_DIV_SELECT; + *bm = BM_PLL_USB_DIV_SELECT; + } else { + BUG(); + } + + return reg; +} + +static unsigned long pll_get_rate(struct clk *clk) +{ + void __iomem *reg; + u32 div, bp, bm; + + reg = pll_get_div_reg_bit(clk, &bp, &bm); + div = (readl_relaxed(reg) & bm) >> bp; + + return (div == 1) ? clk_get_rate(clk->parent) * 22 : + clk_get_rate(clk->parent) * 20; +} + +static int pll_set_rate(struct clk *clk, unsigned long rate) +{ + void __iomem *reg; + u32 val, div, bp, bm; + + if (rate == FREQ_528M) + div = 1; + else if (rate == FREQ_480M) + div = 0; + else + return -EINVAL; + + reg = pll_get_div_reg_bit(clk, &bp, &bm); + val = readl_relaxed(reg); + val &= ~bm; + val |= div << bp; + writel_relaxed(val, reg); + + return 0; +} + +#define pll2_bus_get_rate pll_get_rate +#define pll2_bus_set_rate pll_set_rate +#define pll3_usb_otg_get_rate pll_get_rate +#define pll3_usb_otg_set_rate pll_set_rate +#define pll7_usb_host_get_rate pll_get_rate +#define pll7_usb_host_set_rate pll_set_rate +#define pll4_audio_get_rate pll_av_get_rate +#define pll4_audio_set_rate pll_av_set_rate +#define pll5_video_get_rate pll_av_get_rate +#define pll5_video_set_rate pll_av_set_rate +#define pll6_mlb_get_rate NULL +#define pll6_mlb_set_rate NULL + +#define DEF_PLL(name) \ + static struct clk name = { \ + .enable = pll_enable, \ + .disable = pll_disable, \ + .get_rate = name##_get_rate, \ + .set_rate = name##_set_rate, \ + .parent = &osc_clk, \ + } + +DEF_PLL(pll1_sys); +DEF_PLL(pll2_bus); +DEF_PLL(pll3_usb_otg); +DEF_PLL(pll4_audio); +DEF_PLL(pll5_video); +DEF_PLL(pll6_mlb); +DEF_PLL(pll7_usb_host); +DEF_PLL(pll8_enet); + +static unsigned long pfd_get_rate(struct clk *clk) +{ + u64 tmp = (u64) clk_get_rate(clk->parent) * 18; + u32 frac, bp_frac; + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.enable(&apbh_dma_clk); + + bp_frac = clk->enable_shift - 7; + frac = readl_relaxed(clk->enable_reg) >> bp_frac & PFD_FRAC_MASK; + do_div(tmp, frac); + + return tmp; +} + +static int pfd_set_rate(struct clk *clk, unsigned long rate) +{ + u32 val, frac, bp_frac; + u64 tmp = (u64) clk_get_rate(clk->parent) * 18; + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.enable(&apbh_dma_clk); + + /* + * Round up the divider so that we don't set a rate + * higher than what is requested + */ + tmp += rate / 2; + do_div(tmp, rate); + frac = tmp; + frac = (frac < 12) ? 12 : frac; + frac = (frac > 35) ? 35 : frac; + + /* + * The frac field always starts from 7 bits lower + * position of enable bit + */ + bp_frac = clk->enable_shift - 7; + val = readl_relaxed(clk->enable_reg); + val &= ~(PFD_FRAC_MASK << bp_frac); + val |= frac << bp_frac; + writel_relaxed(val, clk->enable_reg); + + tmp = (u64) clk_get_rate(clk->parent) * 18; + do_div(tmp, frac); + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.disable(&apbh_dma_clk); + + return 0; +} + +static unsigned long pfd_round_rate(struct clk *clk, unsigned long rate) +{ + u32 frac; + u64 tmp; + + tmp = (u64) clk_get_rate(clk->parent) * 18; + tmp += rate / 2; + do_div(tmp, rate); + frac = tmp; + frac = (frac < 12) ? 12 : frac; + frac = (frac > 35) ? 35 : frac; + tmp = (u64) clk_get_rate(clk->parent) * 18; + do_div(tmp, frac); + + return tmp; +} + +static int pfd_enable(struct clk *clk) +{ + u32 val; + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.enable(&apbh_dma_clk); + + val = readl_relaxed(clk->enable_reg); + val &= ~(1 << clk->enable_shift); + writel_relaxed(val, clk->enable_reg); + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.disable(&apbh_dma_clk); + + return 0; +} + +static void pfd_disable(struct clk *clk) +{ + u32 val; + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.enable(&apbh_dma_clk); + + val = readl_relaxed(clk->enable_reg); + val |= 1 << clk->enable_shift; + writel_relaxed(val, clk->enable_reg); + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.disable(&apbh_dma_clk); +} + +#define DEF_PFD(name, er, es, p) \ + static struct clk name = { \ + .enable_reg = er, \ + .enable_shift = es, \ + .enable = pfd_enable, \ + .disable = pfd_disable, \ + .get_rate = pfd_get_rate, \ + .set_rate = pfd_set_rate, \ + .round_rate = pfd_round_rate, \ + .parent = p, \ + } + +DEF_PFD(pll2_pfd_352m, PFD_528, PFD0, &pll2_bus); +DEF_PFD(pll2_pfd_594m, PFD_528, PFD1, &pll2_bus); +DEF_PFD(pll2_pfd_400m, PFD_528, PFD2, &pll2_bus); +DEF_PFD(pll3_pfd_720m, PFD_480, PFD0, &pll3_usb_otg); +DEF_PFD(pll3_pfd_540m, PFD_480, PFD1, &pll3_usb_otg); +DEF_PFD(pll3_pfd_508m, PFD_480, PFD2, &pll3_usb_otg); +DEF_PFD(pll3_pfd_454m, PFD_480, PFD3, &pll3_usb_otg); + +static unsigned long pll2_200m_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 2; +} + +static struct clk pll2_200m = { + .parent = &pll2_pfd_400m, + .get_rate = pll2_200m_get_rate, +}; + +static unsigned long pll3_120m_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 4; +} + +static struct clk pll3_120m = { + .parent = &pll3_usb_otg, + .get_rate = pll3_120m_get_rate, +}; + +static unsigned long pll3_80m_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 6; +} + +static struct clk pll3_80m = { + .parent = &pll3_usb_otg, + .get_rate = pll3_80m_get_rate, +}; + +static unsigned long pll3_60m_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 8; +} + +static struct clk pll3_60m = { + .parent = &pll3_usb_otg, + .get_rate = pll3_60m_get_rate, +}; + +static int pll1_sw_clk_set_parent(struct clk *clk, struct clk *parent) +{ + u32 val = readl_relaxed(CCSR); + + if (parent == &pll1_sys) { + val &= ~BM_CCSR_PLL1_SW_SEL; + val &= ~BM_CCSR_STEP_SEL; + } else if (parent == &osc_clk) { + val |= BM_CCSR_PLL1_SW_SEL; + val &= ~BM_CCSR_STEP_SEL; + } else if (parent == &pll2_pfd_400m) { + val |= BM_CCSR_PLL1_SW_SEL; + val |= BM_CCSR_STEP_SEL; + } else { + return -EINVAL; + } + + writel_relaxed(val, CCSR); + + return 0; +} + +static struct clk pll1_sw_clk = { + .parent = &pll1_sys, + .set_parent = pll1_sw_clk_set_parent, +}; + +static void calc_pred_podf_dividers(u32 div, u32 *pred, u32 *podf) +{ + u32 min_pred, temp_pred, old_err, err; + + if (div >= 512) { + *pred = 8; + *podf = 64; + } else if (div >= 8) { + min_pred = (div - 1) / 64 + 1; + old_err = 8; + for (temp_pred = 8; temp_pred >= min_pred; temp_pred--) { + err = div % temp_pred; + if (err == 0) { + *pred = temp_pred; + break; + } + err = temp_pred - err; + if (err < old_err) { + old_err = err; + *pred = temp_pred; + } + } + *podf = (div + *pred - 1) / *pred; + } else if (div < 8) { + *pred = div; + *podf = 1; + } +} + +static int _clk_enable(struct clk *clk) +{ + u32 reg; + reg = readl_relaxed(clk->enable_reg); + reg |= 0x3 << clk->enable_shift; + writel_relaxed(reg, clk->enable_reg); + + return 0; +} + +static void _clk_disable(struct clk *clk) +{ + u32 reg; + reg = readl_relaxed(clk->enable_reg); + reg &= ~(0x3 << clk->enable_shift); + writel_relaxed(reg, clk->enable_reg); +} + +struct divider { + struct clk *clk; + void __iomem *reg; + u32 bp_pred; + u32 bm_pred; + u32 bp_podf; + u32 bm_podf; +}; + +#define DEF_CLK_DIV1(d, c, r, b) \ + static struct divider d = { \ + .clk = c, \ + .reg = r, \ + .bp_podf = BP_##r##_##b##_PODF, \ + .bm_podf = BM_##r##_##b##_PODF, \ + } + +DEF_CLK_DIV1(arm_div, &arm_clk, CACRR, ARM); +DEF_CLK_DIV1(ipg_div, &ipg_clk, CBCDR, IPG); +DEF_CLK_DIV1(ahb_div, &ahb_clk, CBCDR, AHB); +DEF_CLK_DIV1(axi_div, &axi_clk, CBCDR, AXI); +DEF_CLK_DIV1(mmdc_ch0_axi_div, &mmdc_ch0_axi_clk, CBCDR, MMDC_CH0_AXI); +DEF_CLK_DIV1(mmdc_ch1_axi_div, &mmdc_ch1_axi_clk, CBCDR, MMDC_CH1_AXI); +DEF_CLK_DIV1(periph_clk2_div, &periph_clk2_clk, CBCDR, PERIPH_CLK2); +DEF_CLK_DIV1(periph2_clk2_div, &periph2_clk2_clk, CBCDR, PERIPH2_CLK2); +DEF_CLK_DIV1(gpu2d_core_div, &gpu2d_core_clk, CBCMR, GPU2D_CORE); +DEF_CLK_DIV1(gpu3d_core_div, &gpu3d_core_clk, CBCMR, GPU3D_CORE); +DEF_CLK_DIV1(gpu3d_shader_div, &gpu3d_shader_clk, CBCMR, GPU3D_SHADER); +DEF_CLK_DIV1(ipg_perclk_div, &ipg_perclk, CSCMR1, PERCLK); +DEF_CLK_DIV1(emi_div, &emi_clk, CSCMR1, EMI); +DEF_CLK_DIV1(emi_slow_div, &emi_slow_clk, CSCMR1, EMI_SLOW); +DEF_CLK_DIV1(can_div, &can1_clk, CSCMR2, CAN); +DEF_CLK_DIV1(uart_div, &uart_clk, CSCDR1, UART); +DEF_CLK_DIV1(usdhc1_div, &usdhc1_clk, CSCDR1, USDHC1); +DEF_CLK_DIV1(usdhc2_div, &usdhc2_clk, CSCDR1, USDHC2); +DEF_CLK_DIV1(usdhc3_div, &usdhc3_clk, CSCDR1, USDHC3); +DEF_CLK_DIV1(usdhc4_div, &usdhc4_clk, CSCDR1, USDHC4); +DEF_CLK_DIV1(vpu_div, &vpu_clk, CSCDR1, VPU_AXI); +DEF_CLK_DIV1(hsi_tx_div, &hsi_tx_clk, CDCDR, HSI_TX); +DEF_CLK_DIV1(ipu1_di0_pre_div, &ipu1_di0_pre_clk, CHSCCDR, IPU1_DI0_PRE); +DEF_CLK_DIV1(ipu1_di1_pre_div, &ipu1_di1_pre_clk, CHSCCDR, IPU1_DI1_PRE); +DEF_CLK_DIV1(ipu2_di0_pre_div, &ipu2_di0_pre_clk, CSCDR2, IPU2_DI0_PRE); +DEF_CLK_DIV1(ipu2_di1_pre_div, &ipu2_di1_pre_clk, CSCDR2, IPU2_DI1_PRE); +DEF_CLK_DIV1(ipu1_div, &ipu1_clk, CSCDR3, IPU1_HSP); +DEF_CLK_DIV1(ipu2_div, &ipu2_clk, CSCDR3, IPU2_HSP); + +#define DEF_CLK_DIV2(d, c, r, b) \ + static struct divider d = { \ + .clk = c, \ + .reg = r, \ + .bp_pred = BP_##r##_##b##_PRED, \ + .bm_pred = BM_##r##_##b##_PRED, \ + .bp_podf = BP_##r##_##b##_PODF, \ + .bm_podf = BM_##r##_##b##_PODF, \ + } + +DEF_CLK_DIV2(ssi1_div, &ssi1_clk, CS1CDR, SSI1); +DEF_CLK_DIV2(ssi3_div, &ssi3_clk, CS1CDR, SSI3); +DEF_CLK_DIV2(esai_div, &esai_clk, CS1CDR, ESAI); +DEF_CLK_DIV2(ssi2_div, &ssi2_clk, CS2CDR, SSI2); +DEF_CLK_DIV2(enfc_div, &enfc_clk, CS2CDR, ENFC); +DEF_CLK_DIV2(spdif_div, &spdif_clk, CDCDR, SPDIF); +DEF_CLK_DIV2(asrc_serial_div, &asrc_serial_clk, CDCDR, ASRC_SERIAL); + +static struct divider *dividers[] = { + &arm_div, + &ipg_div, + &ahb_div, + &axi_div, + &mmdc_ch0_axi_div, + &mmdc_ch1_axi_div, + &periph_clk2_div, + &periph2_clk2_div, + &gpu2d_core_div, + &gpu3d_core_div, + &gpu3d_shader_div, + &ipg_perclk_div, + &emi_div, + &emi_slow_div, + &can_div, + &uart_div, + &usdhc1_div, + &usdhc2_div, + &usdhc3_div, + &usdhc4_div, + &vpu_div, + &hsi_tx_div, + &ipu1_di0_pre_div, + &ipu1_di1_pre_div, + &ipu2_di0_pre_div, + &ipu2_di1_pre_div, + &ipu1_div, + &ipu2_div, + &ssi1_div, + &ssi3_div, + &esai_div, + &ssi2_div, + &enfc_div, + &spdif_div, + &asrc_serial_div, +}; + +static unsigned long ldb_di_clk_get_rate(struct clk *clk) +{ + u32 val = readl_relaxed(CSCMR2); + + val &= (clk == &ldb_di0_clk) ? BM_CSCMR2_LDB_DI0_IPU_DIV : + BM_CSCMR2_LDB_DI1_IPU_DIV; + if (val) + return clk_get_rate(clk->parent) / 7; + else + return clk_get_rate(clk->parent) * 2 / 7; +} + +static int ldb_di_clk_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + u32 val = readl_relaxed(CSCMR2); + + if (rate * 7 <= parent_rate + parent_rate / 20) + val |= BM_CSCMR2_LDB_DI0_IPU_DIV; + else + val &= ~BM_CSCMR2_LDB_DI0_IPU_DIV; + + writel_relaxed(val, CSCMR2); + + return 0; +} + +static unsigned long ldb_di_clk_round_rate(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + + if (rate * 7 <= parent_rate + parent_rate / 20) + return parent_rate / 7; + else + return 2 * parent_rate / 7; +} + +static unsigned long _clk_get_rate(struct clk *clk) +{ + struct divider *d; + u32 val, pred, podf; + int i, num; + + if (clk == &ldb_di0_clk || clk == &ldb_di1_clk) + return ldb_di_clk_get_rate(clk); + + num = ARRAY_SIZE(dividers); + for (i = 0; i < num; i++) + if (dividers[i]->clk == clk) { + d = dividers[i]; + break; + } + if (i == num) + return clk_get_rate(clk->parent); + + val = readl_relaxed(d->reg); + pred = ((val & d->bm_pred) >> d->bp_pred) + 1; + podf = ((val & d->bm_podf) >> d->bp_podf) + 1; + + return clk_get_rate(clk->parent) / (pred * podf); +} + +static int clk_busy_wait(struct clk *clk) +{ + int timeout = 0x100000; + u32 bm; + + if (clk == &axi_clk) + bm = BM_CDHIPR_AXI_PODF_BUSY; + else if (clk == &ahb_clk) + bm = BM_CDHIPR_AHB_PODF_BUSY; + else if (clk == &mmdc_ch0_axi_clk) + bm = BM_CDHIPR_MMDC_CH0_PODF_BUSY; + else if (clk == &periph_clk) + bm = BM_CDHIPR_PERIPH_SEL_BUSY; + else if (clk == &arm_clk) + bm = BM_CDHIPR_ARM_PODF_BUSY; + else + return -EINVAL; + + while ((readl_relaxed(CDHIPR) & bm) && --timeout) + cpu_relax(); + + if (unlikely(!timeout)) + return -EBUSY; + + return 0; +} + +static int _clk_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + struct divider *d; + u32 val, div, max_div, pred = 0, podf; + int i, num; + + if (clk == &ldb_di0_clk || clk == &ldb_di1_clk) + return ldb_di_clk_set_rate(clk, rate); + + num = ARRAY_SIZE(dividers); + for (i = 0; i < num; i++) + if (dividers[i]->clk == clk) { + d = dividers[i]; + break; + } + if (i == num) + return -EINVAL; + + max_div = ((d->bm_pred >> d->bp_pred) + 1) * + ((d->bm_pred >> d->bp_pred) + 1); + + div = parent_rate / rate; + if (div == 0) + div++; + + if ((parent_rate / div != rate) || div > max_div) + return -EINVAL; + + if (d->bm_pred) { + calc_pred_podf_dividers(div, &pred, &podf); + } else { + pred = 1; + podf = div; + } + + val = readl_relaxed(d->reg); + val &= ~(d->bm_pred | d->bm_podf); + val |= (pred - 1) << d->bp_pred | (podf - 1) << d->bp_podf; + writel_relaxed(val, d->reg); + + if (clk == &axi_clk || clk == &ahb_clk || + clk == &mmdc_ch0_axi_clk || clk == &arm_clk) + return clk_busy_wait(clk); + + return 0; +} + +static unsigned long _clk_round_rate(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + u32 div_max, pred = 0, podf; + struct divider *d; + int i, num; + + if (clk == &ldb_di0_clk || clk == &ldb_di1_clk) + return ldb_di_clk_round_rate(clk, rate); + + num = ARRAY_SIZE(dividers); + for (i = 0; i < num; i++) + if (dividers[i]->clk == clk) { + d = dividers[i]; + break; + } + if (i == num) + return -EINVAL; + + if (div == 0 || parent_rate % rate) + div++; + + if (d->bm_pred) { + calc_pred_podf_dividers(div, &pred, &podf); + div = pred * podf; + } else { + div_max = (d->bm_podf >> d->bp_podf) + 1; + if (div > div_max) + div = div_max; + } + + return parent_rate / div; +} + +struct multiplexer { + struct clk *clk; + void __iomem *reg; + u32 bp; + u32 bm; + int pnum; + struct clk *parents[]; +}; + +static struct multiplexer axi_mux = { + .clk = &axi_clk, + .reg = CBCDR, + .bp = BP_CBCDR_AXI_SEL, + .bm = BM_CBCDR_AXI_SEL, + .parents = { + &periph_clk, + &pll2_pfd_400m, + &pll3_pfd_540m, + NULL + }, +}; + +static struct multiplexer periph_mux = { + .clk = &periph_clk, + .reg = CBCDR, + .bp = BP_CBCDR_PERIPH_CLK_SEL, + .bm = BM_CBCDR_PERIPH_CLK_SEL, + .parents = { + &periph_pre_clk, + &periph_clk2_clk, + NULL + }, +}; + +static struct multiplexer periph_pre_mux = { + .clk = &periph_pre_clk, + .reg = CBCMR, + .bp = BP_CBCMR_PRE_PERIPH_CLK_SEL, + .bm = BM_CBCMR_PRE_PERIPH_CLK_SEL, + .parents = { + &pll2_bus, + &pll2_pfd_400m, + &pll2_pfd_352m, + &pll2_200m, + NULL + }, +}; + +static struct multiplexer periph_clk2_mux = { + .clk = &periph_clk2_clk, + .reg = CBCMR, + .bp = BP_CBCMR_PERIPH_CLK2_SEL, + .bm = BM_CBCMR_PERIPH_CLK2_SEL, + .parents = { + &pll3_usb_otg, + &osc_clk, + NULL + }, +}; + +static struct multiplexer periph2_mux = { + .clk = &periph2_clk, + .reg = CBCDR, + .bp = BP_CBCDR_PERIPH2_CLK_SEL, + .bm = BM_CBCDR_PERIPH2_CLK_SEL, + .parents = { + &periph2_pre_clk, + &periph2_clk2_clk, + NULL + }, +}; + +static struct multiplexer periph2_pre_mux = { + .clk = &periph2_pre_clk, + .reg = CBCMR, + .bp = BP_CBCMR_PRE_PERIPH2_CLK_SEL, + .bm = BM_CBCMR_PRE_PERIPH2_CLK_SEL, + .parents = { + &pll2_bus, + &pll2_pfd_400m, + &pll2_pfd_352m, + &pll2_200m, + NULL + }, +}; + +static struct multiplexer periph2_clk2_mux = { + .clk = &periph2_clk2_clk, + .reg = CBCMR, + .bp = BP_CBCMR_PERIPH2_CLK2_SEL, + .bm = BM_CBCMR_PERIPH2_CLK2_SEL, + .parents = { + &pll3_usb_otg, + &osc_clk, + NULL + }, +}; + +static struct multiplexer gpu2d_axi_mux = { + .clk = &gpu2d_axi_clk, + .reg = CBCMR, + .bp = BP_CBCMR_GPU2D_AXI_SEL, + .bm = BM_CBCMR_GPU2D_AXI_SEL, + .parents = { + &axi_clk, + &ahb_clk, + NULL + }, +}; + +static struct multiplexer gpu3d_axi_mux = { + .clk = &gpu3d_axi_clk, + .reg = CBCMR, + .bp = BP_CBCMR_GPU3D_AXI_SEL, + .bm = BM_CBCMR_GPU3D_AXI_SEL, + .parents = { + &axi_clk, + &ahb_clk, + NULL + }, +}; + +static struct multiplexer gpu3d_core_mux = { + .clk = &gpu3d_core_clk, + .reg = CBCMR, + .bp = BP_CBCMR_GPU3D_CORE_SEL, + .bm = BM_CBCMR_GPU3D_CORE_SEL, + .parents = { + &mmdc_ch0_axi_clk, + &pll3_usb_otg, + &pll2_pfd_594m, + &pll2_pfd_400m, + NULL + }, +}; + +static struct multiplexer gpu3d_shader_mux = { + .clk = &gpu3d_shader_clk, + .reg = CBCMR, + .bp = BP_CBCMR_GPU3D_SHADER_SEL, + .bm = BM_CBCMR_GPU3D_SHADER_SEL, + .parents = { + &mmdc_ch0_axi_clk, + &pll3_usb_otg, + &pll2_pfd_594m, + &pll3_pfd_720m, + NULL + }, +}; + +static struct multiplexer pcie_axi_mux = { + .clk = &pcie_clk, + .reg = CBCMR, + .bp = BP_CBCMR_PCIE_AXI_SEL, + .bm = BM_CBCMR_PCIE_AXI_SEL, + .parents = { + &axi_clk, + &ahb_clk, + NULL + }, +}; + +static struct multiplexer vdo_axi_mux = { + .clk = &vdo_axi_clk, + .reg = CBCMR, + .bp = BP_CBCMR_VDO_AXI_SEL, + .bm = BM_CBCMR_VDO_AXI_SEL, + .parents = { + &axi_clk, + &ahb_clk, + NULL + }, +}; + +static struct multiplexer vpu_axi_mux = { + .clk = &vpu_clk, + .reg = CBCMR, + .bp = BP_CBCMR_VPU_AXI_SEL, + .bm = BM_CBCMR_VPU_AXI_SEL, + .parents = { + &axi_clk, + &pll2_pfd_400m, + &pll2_pfd_352m, + NULL + }, +}; + +static struct multiplexer gpu2d_core_mux = { + .clk = &gpu2d_core_clk, + .reg = CBCMR, + .bp = BP_CBCMR_GPU2D_CORE_SEL, + .bm = BM_CBCMR_GPU2D_CORE_SEL, + .parents = { + &axi_clk, + &pll3_usb_otg, + &pll2_pfd_352m, + &pll2_pfd_400m, + NULL + }, +}; + +#define DEF_SSI_MUX(id) \ + static struct multiplexer ssi##id##_mux = { \ + .clk = &ssi##id##_clk, \ + .reg = CSCMR1, \ + .bp = BP_CSCMR1_SSI##id##_SEL, \ + .bm = BM_CSCMR1_SSI##id##_SEL, \ + .parents = { \ + &pll3_pfd_508m, \ + &pll3_pfd_454m, \ + &pll4_audio, \ + NULL \ + }, \ + } + +DEF_SSI_MUX(1); +DEF_SSI_MUX(2); +DEF_SSI_MUX(3); + +#define DEF_USDHC_MUX(id) \ + static struct multiplexer usdhc##id##_mux = { \ + .clk = &usdhc##id##_clk, \ + .reg = CSCMR1, \ + .bp = BP_CSCMR1_USDHC##id##_SEL, \ + .bm = BM_CSCMR1_USDHC##id##_SEL, \ + .parents = { \ + &pll2_pfd_400m, \ + &pll2_pfd_352m, \ + NULL \ + }, \ + } + +DEF_USDHC_MUX(1); +DEF_USDHC_MUX(2); +DEF_USDHC_MUX(3); +DEF_USDHC_MUX(4); + +static struct multiplexer emi_mux = { + .clk = &emi_clk, + .reg = CSCMR1, + .bp = BP_CSCMR1_EMI_SEL, + .bm = BM_CSCMR1_EMI_SEL, + .parents = { + &axi_clk, + &pll3_usb_otg, + &pll2_pfd_400m, + &pll2_pfd_352m, + NULL + }, +}; + +static struct multiplexer emi_slow_mux = { + .clk = &emi_slow_clk, + .reg = CSCMR1, + .bp = BP_CSCMR1_EMI_SLOW_SEL, + .bm = BM_CSCMR1_EMI_SLOW_SEL, + .parents = { + &axi_clk, + &pll3_usb_otg, + &pll2_pfd_400m, + &pll2_pfd_352m, + NULL + }, +}; + +static struct multiplexer esai_mux = { + .clk = &esai_clk, + .reg = CSCMR2, + .bp = BP_CSCMR2_ESAI_SEL, + .bm = BM_CSCMR2_ESAI_SEL, + .parents = { + &pll4_audio, + &pll3_pfd_508m, + &pll3_pfd_454m, + &pll3_usb_otg, + NULL + }, +}; + +#define DEF_LDB_DI_MUX(id) \ + static struct multiplexer ldb_di##id##_mux = { \ + .clk = &ldb_di##id##_clk, \ + .reg = CS2CDR, \ + .bp = BP_CS2CDR_LDB_DI##id##_SEL, \ + .bm = BM_CS2CDR_LDB_DI##id##_SEL, \ + .parents = { \ + &pll5_video, \ + &pll2_pfd_352m, \ + &pll2_pfd_400m, \ + &pll3_pfd_540m, \ + &pll3_usb_otg, \ + NULL \ + }, \ + } + +DEF_LDB_DI_MUX(0); +DEF_LDB_DI_MUX(1); + +static struct multiplexer enfc_mux = { + .clk = &enfc_clk, + .reg = CS2CDR, + .bp = BP_CS2CDR_ENFC_SEL, + .bm = BM_CS2CDR_ENFC_SEL, + .parents = { + &pll2_pfd_352m, + &pll2_bus, + &pll3_usb_otg, + &pll2_pfd_400m, + NULL + }, +}; + +static struct multiplexer spdif_mux = { + .clk = &spdif_clk, + .reg = CDCDR, + .bp = BP_CDCDR_SPDIF_SEL, + .bm = BM_CDCDR_SPDIF_SEL, + .parents = { + &pll4_audio, + &pll3_pfd_508m, + &pll3_pfd_454m, + &pll3_usb_otg, + NULL + }, +}; + +static struct multiplexer asrc_serial_mux = { + .clk = &asrc_serial_clk, + .reg = CDCDR, + .bp = BP_CDCDR_ASRC_SERIAL_SEL, + .bm = BM_CDCDR_ASRC_SERIAL_SEL, + .parents = { + &pll4_audio, + &pll3_pfd_508m, + &pll3_pfd_454m, + &pll3_usb_otg, + NULL + }, +}; + +static struct multiplexer hsi_tx_mux = { + .clk = &hsi_tx_clk, + .reg = CDCDR, + .bp = BP_CDCDR_HSI_TX_SEL, + .bm = BM_CDCDR_HSI_TX_SEL, + .parents = { + &pll3_120m, + &pll2_pfd_400m, + NULL + }, +}; + +#define DEF_IPU_DI_PRE_MUX(r, i, d) \ + static struct multiplexer ipu##i##_di##d##_pre_mux = { \ + .clk = &ipu##i##_di##d##_pre_clk, \ + .reg = r, \ + .bp = BP_##r##_IPU##i##_DI##d##_PRE_SEL, \ + .bm = BM_##r##_IPU##i##_DI##d##_PRE_SEL, \ + .parents = { \ + &mmdc_ch0_axi_clk, \ + &pll3_usb_otg, \ + &pll5_video, \ + &pll2_pfd_352m, \ + &pll2_pfd_400m, \ + &pll3_pfd_540m, \ + NULL \ + }, \ + } + +DEF_IPU_DI_PRE_MUX(CHSCCDR, 1, 0); +DEF_IPU_DI_PRE_MUX(CHSCCDR, 1, 1); +DEF_IPU_DI_PRE_MUX(CSCDR2, 2, 0); +DEF_IPU_DI_PRE_MUX(CSCDR2, 2, 1); + +#define DEF_IPU_DI_MUX(r, i, d) \ + static struct multiplexer ipu##i##_di##d##_mux = { \ + .clk = &ipu##i##_di##d##_clk, \ + .reg = r, \ + .bp = BP_##r##_IPU##i##_DI##d##_SEL, \ + .bm = BM_##r##_IPU##i##_DI##d##_SEL, \ + .parents = { \ + &ipu##i##_di##d##_pre_clk, \ + &dummy_clk, \ + &dummy_clk, \ + &ldb_di0_clk, \ + &ldb_di1_clk, \ + NULL \ + }, \ + } + +DEF_IPU_DI_MUX(CHSCCDR, 1, 0); +DEF_IPU_DI_MUX(CHSCCDR, 1, 1); +DEF_IPU_DI_MUX(CSCDR2, 2, 0); +DEF_IPU_DI_MUX(CSCDR2, 2, 1); + +#define DEF_IPU_MUX(id) \ + static struct multiplexer ipu##id##_mux = { \ + .clk = &ipu##id##_clk, \ + .reg = CSCDR3, \ + .bp = BP_CSCDR3_IPU##id##_HSP_SEL, \ + .bm = BM_CSCDR3_IPU##id##_HSP_SEL, \ + .parents = { \ + &mmdc_ch0_axi_clk, \ + &pll2_pfd_400m, \ + &pll3_120m, \ + &pll3_pfd_540m, \ + NULL \ + }, \ + } + +DEF_IPU_MUX(1); +DEF_IPU_MUX(2); + +static struct multiplexer *multiplexers[] = { + &axi_mux, + &periph_mux, + &periph_pre_mux, + &periph_clk2_mux, + &periph2_mux, + &periph2_pre_mux, + &periph2_clk2_mux, + &gpu2d_axi_mux, + &gpu3d_axi_mux, + &gpu3d_core_mux, + &gpu3d_shader_mux, + &pcie_axi_mux, + &vdo_axi_mux, + &vpu_axi_mux, + &gpu2d_core_mux, + &ssi1_mux, + &ssi2_mux, + &ssi3_mux, + &usdhc1_mux, + &usdhc2_mux, + &usdhc3_mux, + &usdhc4_mux, + &emi_mux, + &emi_slow_mux, + &esai_mux, + &ldb_di0_mux, + &ldb_di1_mux, + &enfc_mux, + &spdif_mux, + &asrc_serial_mux, + &hsi_tx_mux, + &ipu1_di0_pre_mux, + &ipu1_di0_mux, + &ipu1_di1_pre_mux, + &ipu1_di1_mux, + &ipu2_di0_pre_mux, + &ipu2_di0_mux, + &ipu2_di1_pre_mux, + &ipu2_di1_mux, + &ipu1_mux, + &ipu2_mux, +}; + +static int _clk_set_parent(struct clk *clk, struct clk *parent) +{ + struct multiplexer *m; + int i, num; + u32 val; + + num = ARRAY_SIZE(multiplexers); + for (i = 0; i < num; i++) + if (multiplexers[i]->clk == clk) { + m = multiplexers[i]; + break; + } + if (i == num) + return -EINVAL; + + i = 0; + while (m->parents[i]) { + if (parent == m->parents[i]) + break; + i++; + } + if (!m->parents[i]) + return -EINVAL; + + val = readl_relaxed(m->reg); + val &= ~m->bm; + val |= i << m->bp; + writel_relaxed(val, m->reg); + + if (clk == &periph_clk) + return clk_busy_wait(clk); + + return 0; +} + +#define DEF_NG_CLK(name, p) \ + static struct clk name = { \ + .get_rate = _clk_get_rate, \ + .set_rate = _clk_set_rate, \ + .round_rate = _clk_round_rate, \ + .set_parent = _clk_set_parent, \ + .parent = p, \ + } + +DEF_NG_CLK(periph_clk2_clk, &osc_clk); +DEF_NG_CLK(periph_pre_clk, &pll2_bus); +DEF_NG_CLK(periph_clk, &periph_pre_clk); +DEF_NG_CLK(periph2_clk2_clk, &osc_clk); +DEF_NG_CLK(periph2_pre_clk, &pll2_bus); +DEF_NG_CLK(periph2_clk, &periph2_pre_clk); +DEF_NG_CLK(axi_clk, &periph_clk); +DEF_NG_CLK(emi_clk, &axi_clk); +DEF_NG_CLK(arm_clk, &pll1_sw_clk); +DEF_NG_CLK(ahb_clk, &periph_clk); +DEF_NG_CLK(ipg_clk, &ahb_clk); +DEF_NG_CLK(ipg_perclk, &ipg_clk); +DEF_NG_CLK(ipu1_di0_pre_clk, &pll3_pfd_540m); +DEF_NG_CLK(ipu1_di1_pre_clk, &pll3_pfd_540m); +DEF_NG_CLK(ipu2_di0_pre_clk, &pll3_pfd_540m); +DEF_NG_CLK(ipu2_di1_pre_clk, &pll3_pfd_540m); +DEF_NG_CLK(asrc_serial_clk, &pll3_usb_otg); + +#define DEF_CLK(name, er, es, p, s) \ + static struct clk name = { \ + .enable_reg = er, \ + .enable_shift = es, \ + .enable = _clk_enable, \ + .disable = _clk_disable, \ + .get_rate = _clk_get_rate, \ + .set_rate = _clk_set_rate, \ + .round_rate = _clk_round_rate, \ + .set_parent = _clk_set_parent, \ + .parent = p, \ + .secondary = s, \ + } + +DEF_CLK(aips_tz1_clk, CCGR0, CG0, &ahb_clk, NULL); +DEF_CLK(aips_tz2_clk, CCGR0, CG1, &ahb_clk, NULL); +DEF_CLK(apbh_dma_clk, CCGR0, CG2, &ahb_clk, NULL); +DEF_CLK(asrc_clk, CCGR0, CG3, &pll4_audio, NULL); +DEF_CLK(can1_serial_clk, CCGR0, CG8, &pll3_usb_otg, NULL); +DEF_CLK(can1_clk, CCGR0, CG7, &pll3_usb_otg, &can1_serial_clk); +DEF_CLK(can2_serial_clk, CCGR0, CG10, &pll3_usb_otg, NULL); +DEF_CLK(can2_clk, CCGR0, CG9, &pll3_usb_otg, &can2_serial_clk); +DEF_CLK(ecspi1_clk, CCGR1, CG0, &pll3_60m, NULL); +DEF_CLK(ecspi2_clk, CCGR1, CG1, &pll3_60m, NULL); +DEF_CLK(ecspi3_clk, CCGR1, CG2, &pll3_60m, NULL); +DEF_CLK(ecspi4_clk, CCGR1, CG3, &pll3_60m, NULL); +DEF_CLK(ecspi5_clk, CCGR1, CG4, &pll3_60m, NULL); +DEF_CLK(enet_clk, CCGR1, CG5, &ipg_clk, NULL); +DEF_CLK(esai_clk, CCGR1, CG8, &pll3_usb_otg, NULL); +DEF_CLK(gpt_serial_clk, CCGR1, CG11, &ipg_perclk, NULL); +DEF_CLK(gpt_clk, CCGR1, CG10, &ipg_perclk, &gpt_serial_clk); +DEF_CLK(gpu2d_core_clk, CCGR1, CG12, &pll2_pfd_352m, &gpu2d_axi_clk); +DEF_CLK(gpu3d_core_clk, CCGR1, CG13, &pll2_pfd_594m, &gpu3d_axi_clk); +DEF_CLK(gpu3d_shader_clk, CCGR1, CG13, &pll3_pfd_720m, &gpu3d_axi_clk); +DEF_CLK(hdmi_iahb_clk, CCGR2, CG0, &ahb_clk, NULL); +DEF_CLK(hdmi_isfr_clk, CCGR2, CG2, &pll3_pfd_540m, &hdmi_iahb_clk); +DEF_CLK(i2c1_clk, CCGR2, CG3, &ipg_perclk, NULL); +DEF_CLK(i2c2_clk, CCGR2, CG4, &ipg_perclk, NULL); +DEF_CLK(i2c3_clk, CCGR2, CG5, &ipg_perclk, NULL); +DEF_CLK(iim_clk, CCGR2, CG6, &ipg_clk, NULL); +DEF_CLK(enfc_clk, CCGR2, CG7, &pll2_pfd_352m, NULL); +DEF_CLK(ipu1_clk, CCGR3, CG0, &mmdc_ch0_axi_clk, NULL); +DEF_CLK(ipu1_di0_clk, CCGR3, CG1, &ipu1_di0_pre_clk, NULL); +DEF_CLK(ipu1_di1_clk, CCGR3, CG2, &ipu1_di1_pre_clk, NULL); +DEF_CLK(ipu2_clk, CCGR3, CG3, &mmdc_ch0_axi_clk, NULL); +DEF_CLK(ipu2_di0_clk, CCGR3, CG4, &ipu2_di0_pre_clk, NULL); +DEF_CLK(ipu2_di1_clk, CCGR3, CG5, &ipu2_di1_pre_clk, NULL); +DEF_CLK(ldb_di0_clk, CCGR3, CG6, &pll3_pfd_540m, NULL); +DEF_CLK(ldb_di1_clk, CCGR3, CG7, &pll3_pfd_540m, NULL); +DEF_CLK(hsi_tx_clk, CCGR3, CG8, &pll2_pfd_400m, NULL); +DEF_CLK(mlb_clk, CCGR3, CG9, &pll6_mlb, NULL); +DEF_CLK(mmdc_ch0_ipg_clk, CCGR3, CG12, &ipg_clk, NULL); +DEF_CLK(mmdc_ch0_axi_clk, CCGR3, CG10, &periph_clk, &mmdc_ch0_ipg_clk); +DEF_CLK(mmdc_ch1_ipg_clk, CCGR3, CG13, &ipg_clk, NULL); +DEF_CLK(mmdc_ch1_axi_clk, CCGR3, CG11, &periph2_clk, &mmdc_ch1_ipg_clk); +DEF_CLK(openvg_axi_clk, CCGR3, CG13, &axi_clk, NULL); +DEF_CLK(pwm1_clk, CCGR4, CG8, &ipg_perclk, NULL); +DEF_CLK(pwm2_clk, CCGR4, CG9, &ipg_perclk, NULL); +DEF_CLK(pwm3_clk, CCGR4, CG10, &ipg_perclk, NULL); +DEF_CLK(pwm4_clk, CCGR4, CG11, &ipg_perclk, NULL); +DEF_CLK(gpmi_bch_apb_clk, CCGR4, CG12, &usdhc3_clk, NULL); +DEF_CLK(gpmi_bch_clk, CCGR4, CG13, &usdhc4_clk, &gpmi_bch_apb_clk); +DEF_CLK(gpmi_apb_clk, CCGR4, CG15, &usdhc3_clk, &gpmi_bch_clk); +DEF_CLK(gpmi_io_clk, CCGR4, CG14, &enfc_clk, &gpmi_apb_clk); +DEF_CLK(sdma_clk, CCGR5, CG3, &ahb_clk, NULL); +DEF_CLK(spba_clk, CCGR5, CG6, &ipg_clk, NULL); +DEF_CLK(spdif_clk, CCGR5, CG7, &pll3_usb_otg, &spba_clk); +DEF_CLK(ssi1_clk, CCGR5, CG9, &pll3_pfd_508m, NULL); +DEF_CLK(ssi2_clk, CCGR5, CG10, &pll3_pfd_508m, NULL); +DEF_CLK(ssi3_clk, CCGR5, CG11, &pll3_pfd_508m, NULL); +DEF_CLK(uart_serial_clk, CCGR5, CG13, &pll3_usb_otg, NULL); +DEF_CLK(uart_clk, CCGR5, CG12, &pll3_80m, &uart_serial_clk); +DEF_CLK(usboh3_clk, CCGR6, CG0, &ipg_clk, NULL); +DEF_CLK(usdhc1_clk, CCGR6, CG1, &pll2_pfd_400m, NULL); +DEF_CLK(usdhc2_clk, CCGR6, CG2, &pll2_pfd_400m, NULL); +DEF_CLK(usdhc3_clk, CCGR6, CG3, &pll2_pfd_400m, NULL); +DEF_CLK(usdhc4_clk, CCGR6, CG4, &pll2_pfd_400m, NULL); +DEF_CLK(emi_slow_clk, CCGR6, CG5, &axi_clk, NULL); +DEF_CLK(vdo_axi_clk, CCGR6, CG6, &axi_clk, NULL); +DEF_CLK(vpu_clk, CCGR6, CG7, &axi_clk, NULL); + +static int pcie_clk_enable(struct clk *clk) +{ + u32 val; + + val = readl_relaxed(PLL8_ENET); + val |= BM_PLL_ENET_EN_PCIE; + writel_relaxed(val, PLL8_ENET); + + return _clk_enable(clk); +} + +static void pcie_clk_disable(struct clk *clk) +{ + u32 val; + + _clk_disable(clk); + + val = readl_relaxed(PLL8_ENET); + val &= BM_PLL_ENET_EN_PCIE; + writel_relaxed(val, PLL8_ENET); +} + +static struct clk pcie_clk = { + .enable_reg = CCGR4, + .enable_shift = CG0, + .enable = pcie_clk_enable, + .disable = pcie_clk_disable, + .set_parent = _clk_set_parent, + .parent = &axi_clk, + .secondary = &pll8_enet, +}; + +static int sata_clk_enable(struct clk *clk) +{ + u32 val; + + val = readl_relaxed(PLL8_ENET); + val |= BM_PLL_ENET_EN_SATA; + writel_relaxed(val, PLL8_ENET); + + return _clk_enable(clk); +} + +static void sata_clk_disable(struct clk *clk) +{ + u32 val; + + _clk_disable(clk); + + val = readl_relaxed(PLL8_ENET); + val &= BM_PLL_ENET_EN_SATA; + writel_relaxed(val, PLL8_ENET); +} + +static struct clk sata_clk = { + .enable_reg = CCGR5, + .enable_shift = CG2, + .enable = sata_clk_enable, + .disable = sata_clk_disable, + .parent = &ipg_clk, + .secondary = &pll8_enet, +}; + +#define _REGISTER_CLOCK(d, n, c) \ + { \ + .dev_id = d, \ + .con_id = n, \ + .clk = &c, \ + } + +static struct clk_lookup lookups[] = { + _REGISTER_CLOCK("2020000.uart", NULL, uart_clk), + _REGISTER_CLOCK("21e8000.uart", NULL, uart_clk), + _REGISTER_CLOCK("21ec000.uart", NULL, uart_clk), + _REGISTER_CLOCK("21f0000.uart", NULL, uart_clk), + _REGISTER_CLOCK("21f4000.uart", NULL, uart_clk), + _REGISTER_CLOCK("2188000.enet", NULL, enet_clk), + _REGISTER_CLOCK("2190000.usdhc", NULL, usdhc1_clk), + _REGISTER_CLOCK("2194000.usdhc", NULL, usdhc2_clk), + _REGISTER_CLOCK("2198000.usdhc", NULL, usdhc3_clk), + _REGISTER_CLOCK("219c000.usdhc", NULL, usdhc4_clk), + _REGISTER_CLOCK("21a0000.i2c", NULL, i2c1_clk), + _REGISTER_CLOCK("21a4000.i2c", NULL, i2c2_clk), + _REGISTER_CLOCK("21a8000.i2c", NULL, i2c3_clk), + _REGISTER_CLOCK("2008000.ecspi", NULL, ecspi1_clk), + _REGISTER_CLOCK("200c000.ecspi", NULL, ecspi2_clk), + _REGISTER_CLOCK("2010000.ecspi", NULL, ecspi3_clk), + _REGISTER_CLOCK("2014000.ecspi", NULL, ecspi4_clk), + _REGISTER_CLOCK("2018000.ecspi", NULL, ecspi5_clk), + _REGISTER_CLOCK("20ec000.sdma", NULL, sdma_clk), + _REGISTER_CLOCK("20bc000.wdog", NULL, dummy_clk), + _REGISTER_CLOCK("20c0000.wdog", NULL, dummy_clk), + _REGISTER_CLOCK(NULL, "ckih", ckih_clk), + _REGISTER_CLOCK(NULL, "ckil_clk", ckil_clk), + _REGISTER_CLOCK(NULL, "aips_tz1_clk", aips_tz1_clk), + _REGISTER_CLOCK(NULL, "aips_tz2_clk", aips_tz2_clk), + _REGISTER_CLOCK(NULL, "asrc_clk", asrc_clk), + _REGISTER_CLOCK(NULL, "can2_clk", can2_clk), + _REGISTER_CLOCK(NULL, "hdmi_isfr_clk", hdmi_isfr_clk), + _REGISTER_CLOCK(NULL, "iim_clk", iim_clk), + _REGISTER_CLOCK(NULL, "mlb_clk", mlb_clk), + _REGISTER_CLOCK(NULL, "openvg_axi_clk", openvg_axi_clk), + _REGISTER_CLOCK(NULL, "pwm1_clk", pwm1_clk), + _REGISTER_CLOCK(NULL, "pwm2_clk", pwm2_clk), + _REGISTER_CLOCK(NULL, "pwm3_clk", pwm3_clk), + _REGISTER_CLOCK(NULL, "pwm4_clk", pwm4_clk), + _REGISTER_CLOCK(NULL, "gpmi_io_clk", gpmi_io_clk), + _REGISTER_CLOCK(NULL, "usboh3_clk", usboh3_clk), + _REGISTER_CLOCK(NULL, "sata_clk", sata_clk), +}; + +int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) +{ + u32 val = readl_relaxed(CLPCR); + + val &= ~BM_CLPCR_LPM; + switch (mode) { + case WAIT_CLOCKED: + break; + case WAIT_UNCLOCKED: + val |= 0x1 << BP_CLPCR_LPM; + break; + case STOP_POWER_ON: + val |= 0x2 << BP_CLPCR_LPM; + break; + case WAIT_UNCLOCKED_POWER_OFF: + val |= 0x1 << BP_CLPCR_LPM; + val &= ~BM_CLPCR_VSTBY; + val &= ~BM_CLPCR_SBYOS; + val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; + break; + case STOP_POWER_OFF: + val |= 0x2 << BP_CLPCR_LPM; + val |= 0x3 << BP_CLPCR_STBY_COUNT; + val |= BM_CLPCR_VSTBY; + val |= BM_CLPCR_SBYOS; + val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; + break; + default: + return -EINVAL; + } + writel_relaxed(val, CLPCR); + + return 0; +} + +static struct map_desc imx6q_clock_desc[] = { + imx_map_entry(MX6Q, CCM, MT_DEVICE), + imx_map_entry(MX6Q, ANATOP, MT_DEVICE), +}; + +int __init mx6q_clocks_init(void) +{ + struct device_node *np; + void __iomem *base; + int i, irq; + + iotable_init(imx6q_clock_desc, ARRAY_SIZE(imx6q_clock_desc)); + + /* retrieve the freqency of fixed clocks from device tree */ + for_each_compatible_node(np, NULL, "fixed-clock") { + u32 rate; + if (of_property_read_u32(np, "clock-frequency", &rate)) + continue; + + if (of_device_is_compatible(np, "fsl,imx-ckil")) + external_low_reference = rate; + else if (of_device_is_compatible(np, "fsl,imx-ckih1")) + external_high_reference = rate; + else if (of_device_is_compatible(np, "fsl,imx-osc")) + oscillator_reference = rate; + } + + for (i = 0; i < ARRAY_SIZE(lookups); i++) + clkdev_add(&lookups[i]); + + /* only keep necessary clocks on */ + writel_relaxed(0x3 << CG0 | 0x3 << CG1 | 0x3 << CG2, CCGR0); + writel_relaxed(0x3 << CG8 | 0x3 << CG9 | 0x3 << CG10, CCGR2); + writel_relaxed(0x3 << CG10 | 0x3 << CG12, CCGR3); + writel_relaxed(0x3 << CG4 | 0x3 << CG6 | 0x3 << CG7, CCGR4); + writel_relaxed(0x3 << CG0, CCGR5); + writel_relaxed(0, CCGR6); + writel_relaxed(0, CCGR7); + + clk_enable(&uart_clk); + clk_enable(&mmdc_ch0_axi_clk); + + clk_set_rate(&pll4_audio, FREQ_650M); + clk_set_rate(&pll5_video, FREQ_650M); + clk_set_parent(&ipu1_di0_clk, &ipu1_di0_pre_clk); + clk_set_parent(&ipu1_di0_pre_clk, &pll5_video); + clk_set_parent(&gpu3d_shader_clk, &pll2_pfd_594m); + clk_set_rate(&gpu3d_shader_clk, FREQ_594M); + clk_set_parent(&gpu3d_core_clk, &mmdc_ch0_axi_clk); + clk_set_rate(&gpu3d_core_clk, FREQ_528M); + clk_set_parent(&asrc_serial_clk, &pll3_usb_otg); + clk_set_rate(&asrc_serial_clk, 1500000); + clk_set_rate(&enfc_clk, 11000000); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt"); + base = of_iomap(np, 0); + WARN_ON(!base); + irq = irq_of_parse_and_map(np, 0); + mxc_timer_init(&gpt_clk, base, irq); + + return 0; +} diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c new file mode 100644 index 000000000000..e1537f9e45b8 --- /dev/null +++ b/arch/arm/mach-imx/gpc.c @@ -0,0 +1,113 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include + +#define GPC_IMR1 0x008 +#define GPC_PGC_CPU_PDN 0x2a0 + +#define IMR_NUM 4 + +static void __iomem *gpc_base; +static u32 gpc_wake_irqs[IMR_NUM]; +static u32 gpc_saved_imrs[IMR_NUM]; + +void imx_gpc_pre_suspend(void) +{ + void __iomem *reg_imr1 = gpc_base + GPC_IMR1; + int i; + + /* Tell GPC to power off ARM core when suspend */ + writel_relaxed(0x1, gpc_base + GPC_PGC_CPU_PDN); + + for (i = 0; i < IMR_NUM; i++) { + gpc_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4); + writel_relaxed(~gpc_wake_irqs[i], reg_imr1 + i * 4); + } +} + +void imx_gpc_post_resume(void) +{ + void __iomem *reg_imr1 = gpc_base + GPC_IMR1; + int i; + + /* Keep ARM core powered on for other low-power modes */ + writel_relaxed(0x0, gpc_base + GPC_PGC_CPU_PDN); + + for (i = 0; i < IMR_NUM; i++) + writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4); +} + +static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on) +{ + unsigned int idx = d->irq / 32 - 1; + u32 mask; + + /* Sanity check for SPI irq */ + if (d->irq < 32) + return -EINVAL; + + mask = 1 << d->irq % 32; + gpc_wake_irqs[idx] = on ? gpc_wake_irqs[idx] | mask : + gpc_wake_irqs[idx] & ~mask; + + return 0; +} + +static void imx_gpc_irq_unmask(struct irq_data *d) +{ + void __iomem *reg; + u32 val; + + /* Sanity check for SPI irq */ + if (d->irq < 32) + return; + + reg = gpc_base + GPC_IMR1 + (d->irq / 32 - 1) * 4; + val = readl_relaxed(reg); + val &= ~(1 << d->irq % 32); + writel_relaxed(val, reg); +} + +static void imx_gpc_irq_mask(struct irq_data *d) +{ + void __iomem *reg; + u32 val; + + /* Sanity check for SPI irq */ + if (d->irq < 32) + return; + + reg = gpc_base + GPC_IMR1 + (d->irq / 32 - 1) * 4; + val = readl_relaxed(reg); + val |= 1 << (d->irq % 32); + writel_relaxed(val, reg); +} + +void __init imx_gpc_init(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc"); + gpc_base = of_iomap(np, 0); + WARN_ON(!gpc_base); + + /* Register GPC as the secondary interrupt controller behind GIC */ + gic_arch_extn.irq_mask = imx_gpc_irq_mask; + gic_arch_extn.irq_unmask = imx_gpc_irq_unmask; + gic_arch_extn.irq_set_wake = imx_gpc_irq_set_wake; +} diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c new file mode 100644 index 000000000000..c461e98496c3 --- /dev/null +++ b/arch/arm/mach-imx/mmdc.c @@ -0,0 +1,72 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include + +#define MMDC_MAPSR 0x404 +#define BP_MMDC_MAPSR_PSD 0 +#define BP_MMDC_MAPSR_PSS 4 + +static int __devinit imx_mmdc_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + void __iomem *mmdc_base, *reg; + u32 val; + int timeout = 0x400; + + mmdc_base = of_iomap(np, 0); + WARN_ON(!mmdc_base); + + reg = mmdc_base + MMDC_MAPSR; + + /* Enable automatic power saving */ + val = readl_relaxed(reg); + val &= ~(1 << BP_MMDC_MAPSR_PSD); + writel_relaxed(val, reg); + + /* Ensure it's successfully enabled */ + while (!(readl_relaxed(reg) & 1 << BP_MMDC_MAPSR_PSS) && --timeout) + cpu_relax(); + + if (unlikely(!timeout)) { + pr_warn("%s: failed to enable automatic power saving\n", + __func__); + return -EBUSY; + } + + return 0; +} + +static struct of_device_id imx_mmdc_dt_ids[] = { + { .compatible = "fsl,imx6q-mmdc", }, + { /* sentinel */ } +}; + +static struct platform_driver imx_mmdc_driver = { + .driver = { + .name = "imx-mmdc", + .owner = THIS_MODULE, + .of_match_table = imx_mmdc_dt_ids, + }, + .probe = imx_mmdc_probe, +}; + +static int __init imx_mmdc_init(void) +{ + return platform_driver_register(&imx_mmdc_driver); +} +postcore_initcall(imx_mmdc_init); diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c new file mode 100644 index 000000000000..36cacbd0dcc2 --- /dev/null +++ b/arch/arm/mach-imx/src.c @@ -0,0 +1,49 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include + +#define SRC_SCR 0x000 +#define SRC_GPR1 0x020 +#define BP_SRC_SCR_CORE1_RST 14 +#define BP_SRC_SCR_CORE1_ENABLE 22 + +static void __iomem *src_base; + +void imx_enable_cpu(int cpu, bool enable) +{ + u32 mask, val; + + mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1); + val = readl_relaxed(src_base + SRC_SCR); + val = enable ? val | mask : val & ~mask; + writel_relaxed(val, src_base + SRC_SCR); +} + +void imx_set_cpu_jump(int cpu, void *jump_addr) +{ + writel_relaxed(BSYM(virt_to_phys(jump_addr)), + src_base + SRC_GPR1 + cpu * 8); +} + +void __init imx_src_init(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-src"); + src_base = of_iomap(np, 0); + WARN_ON(!src_base); +} -- cgit v1.2.3 From 69c31b7a6e9cd4654ed0bfc7e70b4d7076a5cdb3 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 6 Sep 2011 14:59:40 +0800 Subject: arm/imx6q: add smp and cpu hotplug support It adds smp and cpu hotplug support for imx6q. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/Kconfig | 1 + arch/arm/mach-imx/Makefile | 5 ++ arch/arm/mach-imx/head-v7.S | 71 +++++++++++++++++++++++++++ arch/arm/mach-imx/hotplug.c | 44 +++++++++++++++++ arch/arm/mach-imx/localtimer.c | 35 ++++++++++++++ arch/arm/mach-imx/platsmp.c | 85 +++++++++++++++++++++++++++++++++ arch/arm/plat-mxc/include/mach/common.h | 5 ++ 7 files changed, 246 insertions(+) create mode 100644 arch/arm/mach-imx/head-v7.S create mode 100644 arch/arm/mach-imx/hotplug.c create mode 100644 arch/arm/mach-imx/localtimer.c create mode 100644 arch/arm/mach-imx/platsmp.c (limited to 'arch') diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 40372a8e301b..66b86489384f 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -611,6 +611,7 @@ config SOC_IMX6Q select ARM_GIC select CACHE_L2X0 select CPU_V7 + select HAVE_ARM_SCU select HAVE_IMX_GPC select HAVE_IMX_MMDC select HAVE_IMX_SRC diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 65218d98a78d..f1098507a887 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -65,4 +65,9 @@ obj-$(CONFIG_DEBUG_LL) += lluart.o obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o obj-$(CONFIG_HAVE_IMX_SRC) += src.o +obj-$(CONFIG_CPU_V7) += head-v7.o +AFLAGS_head-v7.o :=-Wa,-march=armv7-a +obj-$(CONFIG_SMP) += platsmp.o +obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o +obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o diff --git a/arch/arm/mach-imx/head-v7.S b/arch/arm/mach-imx/head-v7.S new file mode 100644 index 000000000000..ede908bca7d5 --- /dev/null +++ b/arch/arm/mach-imx/head-v7.S @@ -0,0 +1,71 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include + + .section ".text.head", "ax" + __CPUINIT + +/* + * The secondary kernel init calls v7_flush_dcache_all before it enables + * the L1; however, the L1 comes out of reset in an undefined state, so + * the clean + invalidate performed by v7_flush_dcache_all causes a bunch + * of cache lines with uninitialized data and uninitialized tags to get + * written out to memory, which does really unpleasant things to the main + * processor. We fix this by performing an invalidate, rather than a + * clean + invalidate, before jumping into the kernel. + * + * This funciton is cloned from arch/arm/mach-tegra/headsmp.S, and needs + * to be called for both secondary cores startup and primary core resume + * procedures. Ideally, it should be moved into arch/arm/mm/cache-v7.S. + */ +ENTRY(v7_invalidate_l1) + mov r0, #0 + mcr p15, 2, r0, c0, c0, 0 + mrc p15, 1, r0, c0, c0, 0 + + ldr r1, =0x7fff + and r2, r1, r0, lsr #13 + + ldr r1, =0x3ff + + and r3, r1, r0, lsr #3 @ NumWays - 1 + add r2, r2, #1 @ NumSets + + and r0, r0, #0x7 + add r0, r0, #4 @ SetShift + + clz r1, r3 @ WayShift + add r4, r3, #1 @ NumWays +1: sub r2, r2, #1 @ NumSets-- + mov r3, r4 @ Temp = NumWays +2: subs r3, r3, #1 @ Temp-- + mov r5, r3, lsl r1 + mov r6, r2, lsl r0 + orr r5, r5, r6 @ Reg = (Temp< +#include +#include + +int platform_cpu_kill(unsigned int cpu) +{ + return 1; +} + +/* + * platform-specific code to shutdown a CPU + * + * Called with IRQs disabled + */ +void platform_cpu_die(unsigned int cpu) +{ + flush_cache_all(); + imx_enable_cpu(cpu, false); + cpu_do_idle(); + + /* We should never return from idle */ + panic("cpu %d unexpectedly exit from shutdown\n", cpu); +} + +int platform_cpu_disable(unsigned int cpu) +{ + /* + * we don't allow CPU 0 to be shutdown (it is still too special + * e.g. clock tick interrupts) + */ + return cpu == 0 ? -EPERM : 0; +} diff --git a/arch/arm/mach-imx/localtimer.c b/arch/arm/mach-imx/localtimer.c new file mode 100644 index 000000000000..3a163515d41f --- /dev/null +++ b/arch/arm/mach-imx/localtimer.c @@ -0,0 +1,35 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include + +/* + * Setup the local clock events for a CPU. + */ +int __cpuinit local_timer_setup(struct clock_event_device *evt) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "arm,smp-twd"); + if (!twd_base) { + twd_base = of_iomap(np, 0); + WARN_ON(!twd_base); + } + evt->irq = irq_of_parse_and_map(np, 0); + twd_timer_setup(evt); + + return 0; +} diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c new file mode 100644 index 000000000000..ab98c6fec9eb --- /dev/null +++ b/arch/arm/mach-imx/platsmp.c @@ -0,0 +1,85 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static void __iomem *scu_base; + +static struct map_desc scu_io_desc __initdata = { + /* .virtual and .pfn are run-time assigned */ + .length = SZ_4K, + .type = MT_DEVICE, +}; + +void __init imx_scu_map_io(void) +{ + unsigned long base; + + /* Get SCU base */ + asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base)); + + scu_io_desc.virtual = IMX_IO_P2V(base); + scu_io_desc.pfn = __phys_to_pfn(base); + iotable_init(&scu_io_desc, 1); + + scu_base = IMX_IO_ADDRESS(base); +} + +void __cpuinit platform_secondary_init(unsigned int cpu) +{ + /* + * if any interrupts are already enabled for the primary + * core (e.g. timer irq), then they will not have been enabled + * for us: do so + */ + gic_secondary_init(0); +} + +int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + imx_set_cpu_jump(cpu, v7_secondary_startup); + imx_enable_cpu(cpu, true); + return 0; +} + +/* + * Initialise the CPU possible map early - this describes the CPUs + * which may be present or become present in the system. + */ +void __init smp_init_cpus(void) +{ + int i, ncores; + + ncores = scu_get_core_count(scu_base); + + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); + + set_smp_cross_call(gic_raise_softirq); +} + +void imx_smp_prepare(void) +{ + scu_enable(scu_base); +} + +void __init platform_smp_prepare_cpus(unsigned int max_cpus) +{ + imx_smp_prepare(); +} diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h index c2258374488a..6340df2284d7 100644 --- a/arch/arm/plat-mxc/include/mach/common.h +++ b/arch/arm/plat-mxc/include/mach/common.h @@ -99,4 +99,9 @@ void gic_handle_irq(struct pt_regs *); #define imx53_handle_irq tzic_handle_irq #define imx6q_handle_irq gic_handle_irq +extern void imx_enable_cpu(int cpu, bool enable); +extern void imx_set_cpu_jump(int cpu, void *jump_addr); +#ifdef CONFIG_SMP +extern void v7_secondary_startup(void); +#endif #endif -- cgit v1.2.3 From 13eed9897a2160272df2804ac3bbd4d91c76e577 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 6 Sep 2011 15:05:25 +0800 Subject: arm/imx6q: add device tree machine support It adds generic device tree based machine support for imx6q. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/Makefile | 2 +- arch/arm/mach-imx/mach-imx6q.c | 84 +++++++++++++++++++++++++++++++++ arch/arm/mm/Kconfig | 2 +- arch/arm/plat-mxc/include/mach/common.h | 13 +++++ 4 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mach-imx/mach-imx6q.c (limited to 'arch') diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index f1098507a887..994ae82ca281 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -70,4 +70,4 @@ AFLAGS_head-v7.o :=-Wa,-march=armv7-a obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o -obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o +obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c new file mode 100644 index 000000000000..8bf5fa349484 --- /dev/null +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -0,0 +1,84 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void __init imx6q_init_machine(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + + imx6q_pm_init(); +} + +static void __init imx6q_map_io(void) +{ + imx_lluart_map_io(); + imx_scu_map_io(); +} + +static void __init imx6q_gpio_add_irq_domain(struct device_node *np, + struct device_node *interrupt_parent) +{ + static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS - + 32 * 7; /* imx6q gets 7 gpio ports */ + + irq_domain_add_simple(np, gpio_irq_base); + gpio_irq_base += 32; +} + +static const struct of_device_id imx6q_irq_match[] __initconst = { + { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, + { .compatible = "fsl,imx6q-gpio", .data = imx6q_gpio_add_irq_domain, }, + { /* sentinel */ } +}; + +static void __init imx6q_init_irq(void) +{ + l2x0_of_init(0, ~0UL); + imx_src_init(); + imx_gpc_init(); + of_irq_init(imx6q_irq_match); +} + +static void __init imx6q_timer_init(void) +{ + mx6q_clocks_init(); +} + +static struct sys_timer imx6q_timer = { + .init = imx6q_timer_init, +}; + +static const char *imx6q_dt_compat[] __initdata = { + "fsl,imx6q-sabreauto", + NULL, +}; + +DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad (Device Tree)") + .map_io = imx6q_map_io, + .init_irq = imx6q_init_irq, + .handle_irq = imx6q_handle_irq, + .timer = &imx6q_timer, + .init_machine = imx6q_init_machine, + .dt_compat = imx6q_dt_compat, +MACHINE_END diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 88633fe01a5d..c3ce146e29fe 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -822,7 +822,7 @@ config CACHE_L2X0 REALVIEW_EB_A9MP || SOC_IMX35 || SOC_IMX31 || MACH_REALVIEW_PBX || \ ARCH_NOMADIK || ARCH_OMAP4 || ARCH_EXYNOS4 || ARCH_TEGRA || \ ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || ARCH_SHMOBILE || \ - ARCH_PRIMA2 || ARCH_ZYNQ || ARCH_CNS3XXX + ARCH_PRIMA2 || ARCH_ZYNQ || ARCH_CNS3XXX || ARCH_MX6 default y select OUTER_CACHE select OUTER_CACHE_SYNC diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h index 6340df2284d7..607b4623af0c 100644 --- a/arch/arm/plat-mxc/include/mach/common.h +++ b/arch/arm/plat-mxc/include/mach/common.h @@ -64,6 +64,7 @@ extern int mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2); extern int mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2); +extern int mx6q_clocks_init(void); extern struct platform_device *mxc_register_gpio(char *name, int id, resource_size_t iobase, resource_size_t iosize, int irq, int irq_high); extern void mxc_set_cpu_type(unsigned int type); @@ -101,7 +102,19 @@ void gic_handle_irq(struct pt_regs *); extern void imx_enable_cpu(int cpu, bool enable); extern void imx_set_cpu_jump(int cpu, void *jump_addr); +#ifdef CONFIG_DEBUG_LL +extern void imx_lluart_map_io(void); +#else +static inline void imx_lluart_map_io(void) {} +#endif #ifdef CONFIG_SMP extern void v7_secondary_startup(void); +extern void imx_scu_map_io(void); +#else +static inline void imx_scu_map_io(void) {} #endif +extern void imx_enable_cpu(int cpu, bool enable); +extern void imx_set_cpu_jump(int cpu, void *jump_addr); +extern void imx_src_init(void); +extern void imx_gpc_init(void); #endif -- cgit v1.2.3 From a1f1c7efb0c1c78b5e84455bb5a6c8b2bee3059c Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 6 Sep 2011 15:08:40 +0800 Subject: arm/imx6q: add suspend/resume support It adds suspend/resume support for imx6q. Signed-off-by: Anson Huang Signed-off-by: Shawn Guo --- arch/arm/mach-imx/Makefile | 2 +- arch/arm/mach-imx/head-v7.S | 28 +++++++++++++ arch/arm/mach-imx/pm-imx6q.c | 70 +++++++++++++++++++++++++++++++++ arch/arm/plat-mxc/include/mach/common.h | 9 +++++ 4 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-imx/pm-imx6q.c (limited to 'arch') diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 994ae82ca281..aba73214c2a8 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -70,4 +70,4 @@ AFLAGS_head-v7.o :=-Wa,-march=armv7-a obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o -obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o +obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o pm-imx6q.o diff --git a/arch/arm/mach-imx/head-v7.S b/arch/arm/mach-imx/head-v7.S index ede908bca7d5..6229efbc70cb 100644 --- a/arch/arm/mach-imx/head-v7.S +++ b/arch/arm/mach-imx/head-v7.S @@ -12,6 +12,7 @@ #include #include +#include #include .section ".text.head", "ax" @@ -69,3 +70,30 @@ ENTRY(v7_secondary_startup) b secondary_startup ENDPROC(v7_secondary_startup) #endif + +/* + * The following code is located into the .data section. This is to + * allow phys_l2x0_saved_regs to be accessed with a relative load + * as we are running on physical address here. + */ + .data + .align + + .macro pl310_resume + ldr r2, phys_l2x0_saved_regs + ldr r0, [r2, #L2X0_R_PHY_BASE] @ get physical base of l2x0 + ldr r1, [r2, #L2X0_R_AUX_CTRL] @ get aux_ctrl value + str r1, [r0, #L2X0_AUX_CTRL] @ restore aux_ctrl + mov r1, #0x1 + str r1, [r0, #L2X0_CTRL] @ re-enable L2 + .endm + +ENTRY(v7_cpu_resume) + bl v7_invalidate_l1 + pl310_resume + b cpu_resume +ENDPROC(v7_cpu_resume) + + .globl phys_l2x0_saved_regs +phys_l2x0_saved_regs: + .long 0 diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c new file mode 100644 index 000000000000..f20f191d7cca --- /dev/null +++ b/arch/arm/mach-imx/pm-imx6q.c @@ -0,0 +1,70 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern unsigned long phys_l2x0_saved_regs; + +static int imx6q_suspend_finish(unsigned long val) +{ + cpu_do_idle(); + return 0; +} + +static int imx6q_pm_enter(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_MEM: + imx6q_set_lpm(STOP_POWER_OFF); + imx_gpc_pre_suspend(); + imx_set_cpu_jump(0, v7_cpu_resume); + /* Zzz ... */ + cpu_suspend(0, imx6q_suspend_finish); + imx_smp_prepare(); + imx_gpc_post_resume(); + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct platform_suspend_ops imx6q_pm_ops = { + .enter = imx6q_pm_enter, + .valid = suspend_valid_only_mem, +}; + +void __init imx6q_pm_init(void) +{ + /* + * The l2x0 core code provides an infrastucture to save and restore + * l2x0 registers across suspend/resume cycle. But because imx6q + * retains L2 content during suspend and needs to resume L2 before + * MMU is enabled, it can only utilize register saving support and + * have to take care of restoring on its own. So we save physical + * address of the data structure used by l2x0 core to save registers, + * and later restore the necessary ones in imx6q resume entry. + */ + phys_l2x0_saved_regs = __pa(&l2x0_saved_regs); + + suspend_set_ops(&imx6q_pm_ops); +} diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h index 607b4623af0c..6a7d993a17a6 100644 --- a/arch/arm/plat-mxc/include/mach/common.h +++ b/arch/arm/plat-mxc/include/mach/common.h @@ -13,6 +13,7 @@ struct platform_device; struct clk; +enum mxc_cpu_pwr_mode; extern void mx1_map_io(void); extern void mx21_map_io(void); @@ -107,14 +108,22 @@ extern void imx_lluart_map_io(void); #else static inline void imx_lluart_map_io(void) {} #endif +extern void v7_cpu_resume(void); +extern u32 *pl310_get_save_ptr(void); #ifdef CONFIG_SMP extern void v7_secondary_startup(void); extern void imx_scu_map_io(void); +extern void imx_smp_prepare(void); #else static inline void imx_scu_map_io(void) {} +static inline void imx_smp_prepare(void) {} #endif extern void imx_enable_cpu(int cpu, bool enable); extern void imx_set_cpu_jump(int cpu, void *jump_addr); extern void imx_src_init(void); extern void imx_gpc_init(void); +extern void imx_gpc_pre_suspend(void); +extern void imx_gpc_post_resume(void); +extern int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode); +extern void imx6q_pm_init(void); #endif -- cgit v1.2.3 From a89cf59b5c344e50b7be3cabb67dc1ed94439b6e Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 27 Sep 2011 13:48:02 +0800 Subject: arm/imx: merge i.MX3 and i.MX6 The patch merges the build of imx3 and imx6. The Kconfig symbol ARCH_IMX_V6_V7 is introduced to replace ARCH_MX3 and ARCH_MX6. Signed-off-by: Sascha Hauer Signed-off-by: Shawn Guo --- arch/arm/Makefile | 3 +-- arch/arm/mach-imx/Kconfig | 7 +++---- arch/arm/mm/Kconfig | 4 ++-- arch/arm/plat-mxc/Kconfig | 18 +++++++----------- 4 files changed, 13 insertions(+), 19 deletions(-) (limited to 'arch') diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 193439eb326f..4e98937f1b2d 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -158,9 +158,8 @@ machine-$(CONFIG_ARCH_MMP) := mmp machine-$(CONFIG_ARCH_MSM) := msm machine-$(CONFIG_ARCH_MV78XX0) := mv78xx0 machine-$(CONFIG_ARCH_IMX_V4_V5) := imx -machine-$(CONFIG_ARCH_MX3) := imx +machine-$(CONFIG_ARCH_IMX_V6_V7) := imx machine-$(CONFIG_ARCH_MX5) := mx5 -machine-$(CONFIG_ARCH_MX6) := imx machine-$(CONFIG_ARCH_MXS) := mxs machine-$(CONFIG_ARCH_NETX) := netx machine-$(CONFIG_ARCH_NOMADIK) := nomadik diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 66b86489384f..b1f782f07f12 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -74,6 +74,7 @@ config SOC_IMX31 select ARCH_MXC_AUDMUX_V2 select ARCH_MX31 select MXC_AVIC + select SMP_ON_UP if SMP config SOC_IMX35 bool @@ -83,6 +84,7 @@ config SOC_IMX35 select HAVE_EPIT select ARCH_MX35 select MXC_AVIC + select SMP_ON_UP if SMP if ARCH_IMX_V4_V5 @@ -351,7 +353,7 @@ config MACH_IMX27IPCAM endif -if ARCH_MX3 +if ARCH_IMX_V6_V7 comment "MX31 platforms:" @@ -601,9 +603,6 @@ config MACH_VPR200 Include support for VPR200 platform. This includes specific configurations for the board and its peripherals. -endif - -if ARCH_MX6 comment "i.MX6 family:" config SOC_IMX6Q diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index c3ce146e29fe..9ab5be07061a 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -819,10 +819,10 @@ config CACHE_FEROCEON_L2_WRITETHROUGH config CACHE_L2X0 bool "Enable the L2x0 outer cache controller" depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || \ - REALVIEW_EB_A9MP || SOC_IMX35 || SOC_IMX31 || MACH_REALVIEW_PBX || \ + REALVIEW_EB_A9MP || ARCH_IMX_V6_V7 || MACH_REALVIEW_PBX || \ ARCH_NOMADIK || ARCH_OMAP4 || ARCH_EXYNOS4 || ARCH_TEGRA || \ ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || ARCH_SHMOBILE || \ - ARCH_PRIMA2 || ARCH_ZYNQ || ARCH_CNS3XXX || ARCH_MX6 + ARCH_PRIMA2 || ARCH_ZYNQ || ARCH_CNS3XXX default y select OUTER_CACHE select OUTER_CACHE_SYNC diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig index 058d1c5f0043..2704951d8cd9 100644 --- a/arch/arm/plat-mxc/Kconfig +++ b/arch/arm/plat-mxc/Kconfig @@ -6,7 +6,7 @@ menu "Freescale MXC Implementations" choice prompt "Freescale CPU family:" - default ARCH_MX3 + default ARCH_IMX_V6_V7 config ARCH_IMX_V4_V5 bool "i.MX1, i.MX21, i.MX25, i.MX27" @@ -16,10 +16,13 @@ config ARCH_IMX_V4_V5 This enables support for systems based on the Freescale i.MX ARMv4 and ARMv5 SoCs -config ARCH_MX3 - bool "MX3-based" +config ARCH_IMX_V6_V7 + bool "i.MX3, i.MX6" + select AUTO_ZRELADDR if !ZBOOT_ROM + select ARM_PATCH_PHYS_VIRT help - This enables support for systems based on the Freescale i.MX3 family + This enables support for systems based on the Freescale i.MX3 and i.MX6 + family. config ARCH_MX5 bool "i.MX50, i.MX51, i.MX53" @@ -29,13 +32,6 @@ config ARCH_MX5 This enables support for machines using Freescale's i.MX50 and i.MX51 processors. -config ARCH_MX6 - bool "i.MX6" - select AUTO_ZRELADDR if !ZBOOT_ROM - select ARM_PATCH_PHYS_VIRT - help - This enables support for systems based on the Freescale i.MX6 family - endchoice source "arch/arm/mach-imx/Kconfig" -- cgit v1.2.3