Merge branch 'next/soc' into next/multiplatform
* next/soc: (50 commits) ARM: OMAP: AM33xx hwmod: fixup SPI after platform_data move MAINTAINERS: add an entry for the BCM2835 ARM sub-architecture ARM: bcm2835: instantiate console UART ARM: bcm2835: add stub clock driver ARM: bcm2835: add system timer ARM: bcm2835: add interrupt controller driver ARM: add infra-structure for BCM2835 and Raspberry Pi ARM: tegra20: add CPU hotplug support ARM: tegra30: add CPU hotplug support ARM: tegra: clean up the common assembly macros into sleep.h ARM: tegra: replace the CPU CAR access code by tegra_cpu_car_ops ARM: tegra: introduce tegra_cpu_car_ops structures ARM: Tegra: Add smp_twd clock for Tegra20 ARM: AM33XX: clock: Add dcan clock aliases for device-tree ARM: OMAP2+: dpll: Add missing soc_is_am33xx() check for common functions ARM: OMAP: omap_device: idle devices with no driver bound ARM: OMAP: omap_device: don't attempt late suspend if no driver bound ARM: OMAP: omap_device: keep track of driver bound status ARM: OMAP3+: hwmod: Add AM33XX HWMOD data ARM: OMAP2+: hwmod: Hook-up am33xx support in omap_hwmod framework ... Change/remove conflict in arch/arm/mach-ux500/clock.c resolved. Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
Коммит
b612a85792
|
@ -0,0 +1,8 @@
|
|||
Broadcom BCM2835 device tree bindings
|
||||
-------------------------------------------
|
||||
|
||||
Boards with the BCM2835 SoC shall have the following properties:
|
||||
|
||||
Required root node property:
|
||||
|
||||
compatible = "brcm,bcm2835";
|
|
@ -0,0 +1,110 @@
|
|||
BCM2835 Top-Level ("ARMCTRL") Interrupt Controller
|
||||
|
||||
The BCM2835 contains a custom top-level interrupt controller, which supports
|
||||
72 interrupt sources using a 2-level register scheme. The interrupt
|
||||
controller, or the HW block containing it, is referred to occasionally
|
||||
as "armctrl" in the SoC documentation, hence naming of this binding.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : should be "brcm,bcm2835-armctrl-ic.txt"
|
||||
- reg : Specifies base physical address and size of the registers.
|
||||
- interrupt-controller : Identifies the node as an interrupt controller
|
||||
- #interrupt-cells : Specifies the number of cells needed to encode an
|
||||
interrupt source. The value shall be 2.
|
||||
|
||||
The 1st cell is the interrupt bank; 0 for interrupts in the "IRQ basic
|
||||
pending" register, or 1/2 respectively for interrupts in the "IRQ pending
|
||||
1/2" register.
|
||||
|
||||
The 2nd cell contains the interrupt number within the bank. Valid values
|
||||
are 0..7 for bank 0, and 0..31 for bank 1.
|
||||
|
||||
The interrupt sources are as follows:
|
||||
|
||||
Bank 0:
|
||||
0: ARM_TIMER
|
||||
1: ARM_MAILBOX
|
||||
2: ARM_DOORBELL_0
|
||||
3: ARM_DOORBELL_1
|
||||
4: VPU0_HALTED
|
||||
5: VPU1_HALTED
|
||||
6: ILLEGAL_TYPE0
|
||||
7: ILLEGAL_TYPE1
|
||||
|
||||
Bank 1:
|
||||
0: TIMER0
|
||||
1: TIMER1
|
||||
2: TIMER2
|
||||
3: TIMER3
|
||||
4: CODEC0
|
||||
5: CODEC1
|
||||
6: CODEC2
|
||||
7: VC_JPEG
|
||||
8: ISP
|
||||
9: VC_USB
|
||||
10: VC_3D
|
||||
11: TRANSPOSER
|
||||
12: MULTICORESYNC0
|
||||
13: MULTICORESYNC1
|
||||
14: MULTICORESYNC2
|
||||
15: MULTICORESYNC3
|
||||
16: DMA0
|
||||
17: DMA1
|
||||
18: VC_DMA2
|
||||
19: VC_DMA3
|
||||
20: DMA4
|
||||
21: DMA5
|
||||
22: DMA6
|
||||
23: DMA7
|
||||
24: DMA8
|
||||
25: DMA9
|
||||
26: DMA10
|
||||
27: DMA11
|
||||
28: DMA12
|
||||
29: AUX
|
||||
30: ARM
|
||||
31: VPUDMA
|
||||
|
||||
Bank 2:
|
||||
0: HOSTPORT
|
||||
1: VIDEOSCALER
|
||||
2: CCP2TX
|
||||
3: SDC
|
||||
4: DSI0
|
||||
5: AVE
|
||||
6: CAM0
|
||||
7: CAM1
|
||||
8: HDMI0
|
||||
9: HDMI1
|
||||
10: PIXELVALVE1
|
||||
11: I2CSPISLV
|
||||
12: DSI1
|
||||
13: PWA0
|
||||
14: PWA1
|
||||
15: CPR
|
||||
16: SMI
|
||||
17: GPIO0
|
||||
18: GPIO1
|
||||
19: GPIO2
|
||||
20: GPIO3
|
||||
21: VC_I2C
|
||||
22: VC_SPI
|
||||
23: VC_I2SPCM
|
||||
24: VC_SDIO
|
||||
25: VC_UART
|
||||
26: SLIMBUS
|
||||
27: VEC
|
||||
28: CPG
|
||||
29: RNG
|
||||
30: VC_ARASANSDIO
|
||||
31: AVSPMON
|
||||
|
||||
Example:
|
||||
|
||||
intc: interrupt-controller {
|
||||
compatible = "brcm,bcm2835-armctrl-ic";
|
||||
reg = <0x7e00b200 0x200>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
BCM2835 System Timer
|
||||
|
||||
The System Timer peripheral provides four 32-bit timer channels and a
|
||||
single 64-bit free running counter. Each channel has an output compare
|
||||
register, which is compared against the 32 least significant bits of the
|
||||
free running counter values, and generates an interrupt.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : should be "brcm,bcm2835-system-timer.txt"
|
||||
- reg : Specifies base physical address and size of the registers.
|
||||
- interrupts : A list of 4 interrupt sinks; one per timer channel.
|
||||
- clock-frequency : The frequency of the clock that drives the counter, in Hz.
|
||||
|
||||
Example:
|
||||
|
||||
timer {
|
||||
compatible = "brcm,bcm2835-system-timer";
|
||||
reg = <0x7e003000 0x1000>;
|
||||
interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
|
||||
clock-frequency = <1000000>;
|
||||
};
|
|
@ -10,6 +10,7 @@ apm Applied Micro Circuits Corporation (APM)
|
|||
arm ARM Ltd.
|
||||
atmel Atmel Corporation
|
||||
bosch Bosch Sensortec GmbH
|
||||
brcm Broadcom Corporation
|
||||
cavium Cavium, Inc.
|
||||
chrp Common Hardware Reference Platform
|
||||
cortina Cortina Systems, Inc.
|
||||
|
|
10
MAINTAINERS
10
MAINTAINERS
|
@ -1612,6 +1612,16 @@ L: netdev@vger.kernel.org
|
|||
S: Supported
|
||||
F: drivers/net/ethernet/broadcom/bnx2x/
|
||||
|
||||
BROADCOM BCM2835 ARM ARCHICTURE
|
||||
M: Stephen Warren <swarren@wwwdotorg.org>
|
||||
L: linux-rpi-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-rpi.git
|
||||
S: Maintained
|
||||
F: arch/arm/mach-bcm2835/
|
||||
F: arch/arm/boot/dts/bcm2835*
|
||||
F: arch/arm/configs/bcm2835_defconfig
|
||||
F: drivers/*/*bcm2835*
|
||||
|
||||
BROADCOM TG3 GIGABIT ETHERNET DRIVER
|
||||
M: Matt Carlson <mcarlson@broadcom.com>
|
||||
M: Michael Chan <mchan@broadcom.com>
|
||||
|
|
|
@ -347,6 +347,23 @@ config ARCH_AT91
|
|||
This enables support for systems based on Atmel
|
||||
AT91RM9200 and AT91SAM9* processors.
|
||||
|
||||
config ARCH_BCM2835
|
||||
bool "Broadcom BCM2835 family"
|
||||
select ARCH_WANT_OPTIONAL_GPIOLIB
|
||||
select ARM_AMBA
|
||||
select ARM_ERRATA_411920
|
||||
select ARM_TIMER_SP804
|
||||
select CLKDEV_LOOKUP
|
||||
select COMMON_CLK
|
||||
select CPU_V6
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select MULTI_IRQ_HANDLER
|
||||
select SPARSE_IRQ
|
||||
select USE_OF
|
||||
help
|
||||
This enables support for the Broadcom BCM2835 SoC. This SoC is
|
||||
use in the Raspberry Pi, and Roku 2 devices.
|
||||
|
||||
config ARCH_BCMRING
|
||||
bool "Broadcom BCMRING"
|
||||
depends on MMU
|
||||
|
@ -674,6 +691,7 @@ config ARCH_TEGRA
|
|||
select MIGHT_HAVE_CACHE_L2X0
|
||||
select ARCH_HAS_CPUFREQ
|
||||
select USE_OF
|
||||
select COMMON_CLK
|
||||
help
|
||||
This enables support for NVIDIA Tegra based systems (Tegra APX,
|
||||
Tegra 6xx and Tegra 2 series).
|
||||
|
|
|
@ -136,6 +136,7 @@ textofs-$(CONFIG_ARCH_MSM8960) := 0x00208000
|
|||
# Machine directory name. This list is sorted alphanumerically
|
||||
# by CONFIG_* macro name.
|
||||
machine-$(CONFIG_ARCH_AT91) := at91
|
||||
machine-$(CONFIG_ARCH_BCM2835) := bcm2835
|
||||
machine-$(CONFIG_ARCH_BCMRING) := bcmring
|
||||
machine-$(CONFIG_ARCH_CLPS711X) := clps711x
|
||||
machine-$(CONFIG_ARCH_CNS3XXX) := cns3xxx
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
/dts-v1/;
|
||||
/memreserve/ 0x0c000000 0x04000000;
|
||||
/include/ "bcm2835.dtsi"
|
||||
|
||||
/ {
|
||||
compatible = "raspberrypi,model-b", "brcm,bcm2835";
|
||||
model = "Raspberry Pi Model B";
|
||||
|
||||
memory {
|
||||
reg = <0 0x10000000>;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,39 @@
|
|||
/include/ "skeleton.dtsi"
|
||||
|
||||
/ {
|
||||
compatible = "brcm,bcm2835";
|
||||
model = "BCM2835";
|
||||
interrupt-parent = <&intc>;
|
||||
|
||||
chosen {
|
||||
bootargs = "earlyprintk console=ttyAMA0";
|
||||
};
|
||||
|
||||
soc {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0x7e000000 0x20000000 0x02000000>;
|
||||
|
||||
timer {
|
||||
compatible = "brcm,bcm2835-system-timer";
|
||||
reg = <0x7e003000 0x1000>;
|
||||
interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
|
||||
clock-frequency = <1000000>;
|
||||
};
|
||||
|
||||
intc: interrupt-controller {
|
||||
compatible = "brcm,bcm2835-armctrl-ic";
|
||||
reg = <0x7e00b200 0x200>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
};
|
||||
|
||||
uart@20201000 {
|
||||
compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
|
||||
reg = <0x7e201000 0x1000>;
|
||||
interrupts = <2 25>;
|
||||
clock-frequency = <3000000>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,95 @@
|
|||
CONFIG_EXPERIMENTAL=y
|
||||
# CONFIG_LOCALVERSION_AUTO is not set
|
||||
CONFIG_SYSVIPC=y
|
||||
CONFIG_BSD_PROCESS_ACCT=y
|
||||
CONFIG_BSD_PROCESS_ACCT_V3=y
|
||||
CONFIG_FHANDLE=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_LOG_BUF_SHIFT=18
|
||||
CONFIG_CGROUP_FREEZER=y
|
||||
CONFIG_CGROUP_DEVICE=y
|
||||
CONFIG_CPUSETS=y
|
||||
CONFIG_CGROUP_CPUACCT=y
|
||||
CONFIG_RESOURCE_COUNTERS=y
|
||||
CONFIG_CGROUP_PERF=y
|
||||
CONFIG_CFS_BANDWIDTH=y
|
||||
CONFIG_RT_GROUP_SCHED=y
|
||||
CONFIG_NAMESPACES=y
|
||||
CONFIG_SCHED_AUTOGROUP=y
|
||||
CONFIG_RELAY=y
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
CONFIG_RD_BZIP2=y
|
||||
CONFIG_RD_LZMA=y
|
||||
CONFIG_RD_XZ=y
|
||||
CONFIG_RD_LZO=y
|
||||
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
|
||||
CONFIG_KALLSYMS_ALL=y
|
||||
CONFIG_EMBEDDED=y
|
||||
# CONFIG_COMPAT_BRK is not set
|
||||
CONFIG_PROFILING=y
|
||||
CONFIG_OPROFILE=y
|
||||
CONFIG_JUMP_LABEL=y
|
||||
# CONFIG_BLOCK is not set
|
||||
CONFIG_ARCH_BCM2835=y
|
||||
CONFIG_PREEMPT_VOLUNTARY=y
|
||||
CONFIG_AEABI=y
|
||||
CONFIG_COMPACTION=y
|
||||
CONFIG_KSM=y
|
||||
CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
|
||||
CONFIG_CLEANCACHE=y
|
||||
CONFIG_SECCOMP=y
|
||||
CONFIG_CC_STACKPROTECTOR=y
|
||||
CONFIG_KEXEC=y
|
||||
CONFIG_CRASH_DUMP=y
|
||||
CONFIG_VFP=y
|
||||
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
|
||||
# CONFIG_SUSPEND is not set
|
||||
CONFIG_DEVTMPFS=y
|
||||
CONFIG_DEVTMPFS_MOUNT=y
|
||||
# CONFIG_STANDALONE is not set
|
||||
# CONFIG_INPUT_MOUSEDEV is not set
|
||||
# CONFIG_INPUT_KEYBOARD is not set
|
||||
# CONFIG_INPUT_MOUSE is not set
|
||||
# CONFIG_SERIO is not set
|
||||
# CONFIG_VT is not set
|
||||
# CONFIG_UNIX98_PTYS is not set
|
||||
# CONFIG_LEGACY_PTYS is not set
|
||||
# CONFIG_DEVKMEM is not set
|
||||
CONFIG_SERIAL_AMBA_PL011=y
|
||||
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
|
||||
CONFIG_TTY_PRINTK=y
|
||||
# CONFIG_HW_RANDOM is not set
|
||||
# CONFIG_HWMON is not set
|
||||
# CONFIG_USB_SUPPORT is not set
|
||||
# CONFIG_IOMMU_SUPPORT is not set
|
||||
# CONFIG_FILE_LOCKING is not set
|
||||
# CONFIG_DNOTIFY is not set
|
||||
# CONFIG_INOTIFY_USER is not set
|
||||
# CONFIG_PROC_FS is not set
|
||||
# CONFIG_SYSFS is not set
|
||||
# CONFIG_MISC_FILESYSTEMS is not set
|
||||
CONFIG_PRINTK_TIME=y
|
||||
# CONFIG_ENABLE_WARN_DEPRECATED is not set
|
||||
# CONFIG_ENABLE_MUST_CHECK is not set
|
||||
CONFIG_UNUSED_SYMBOLS=y
|
||||
CONFIG_LOCKUP_DETECTOR=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_DEBUG_MEMORY_INIT=y
|
||||
CONFIG_BOOT_PRINTK_DELAY=y
|
||||
CONFIG_SCHED_TRACER=y
|
||||
CONFIG_STACK_TRACER=y
|
||||
CONFIG_FUNCTION_PROFILER=y
|
||||
CONFIG_DYNAMIC_DEBUG=y
|
||||
CONFIG_KGDB=y
|
||||
CONFIG_KGDB_KDB=y
|
||||
CONFIG_TEST_KSTRTOX=y
|
||||
CONFIG_STRICT_DEVMEM=y
|
||||
CONFIG_DEBUG_LL=y
|
||||
CONFIG_EARLY_PRINTK=y
|
||||
# CONFIG_XZ_DEC_X86 is not set
|
||||
# CONFIG_XZ_DEC_POWERPC is not set
|
||||
# CONFIG_XZ_DEC_IA64 is not set
|
||||
# CONFIG_XZ_DEC_ARM is not set
|
||||
# CONFIG_XZ_DEC_ARMTHUMB is not set
|
||||
# CONFIG_XZ_DEC_SPARC is not set
|
|
@ -8,6 +8,7 @@ CONFIG_LOG_BUF_SHIFT=16
|
|||
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
|
||||
CONFIG_SYSCTL_SYSCALL=y
|
||||
CONFIG_EMBEDDED=y
|
||||
CONFIG_PERF_EVENTS=y
|
||||
CONFIG_SLAB=y
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
# CONFIG_IOSCHED_DEADLINE is not set
|
||||
|
|
|
@ -14,6 +14,7 @@ CONFIG_NAMESPACES=y
|
|||
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
|
||||
CONFIG_SYSCTL_SYSCALL=y
|
||||
CONFIG_EMBEDDED=y
|
||||
CONFIG_PERF_EVENTS=y
|
||||
CONFIG_SLAB=y
|
||||
CONFIG_MODULES=y
|
||||
CONFIG_MODULE_FORCE_LOAD=y
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
obj-y += bcm2835.o
|
|
@ -0,0 +1,5 @@
|
|||
zreladdr-y := 0x00008000
|
||||
params_phys-y := 0x00000100
|
||||
initrd_phys-y := 0x00800000
|
||||
|
||||
dtb-y += bcm2835-rpi-b.dtb
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (C) 2010 Broadcom
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/irqchip/bcm2835.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/bcm2835_timer.h>
|
||||
#include <linux/clk/bcm2835.h>
|
||||
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/map.h>
|
||||
|
||||
#include <mach/bcm2835_soc.h>
|
||||
|
||||
static struct map_desc io_map __initdata = {
|
||||
.virtual = BCM2835_PERIPH_VIRT,
|
||||
.pfn = __phys_to_pfn(BCM2835_PERIPH_PHYS),
|
||||
.length = BCM2835_PERIPH_SIZE,
|
||||
.type = MT_DEVICE
|
||||
};
|
||||
|
||||
void __init bcm2835_map_io(void)
|
||||
{
|
||||
iotable_init(&io_map, 1);
|
||||
}
|
||||
|
||||
void __init bcm2835_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
bcm2835_init_clocks();
|
||||
|
||||
ret = of_platform_populate(NULL, of_default_bus_match_table, NULL,
|
||||
NULL);
|
||||
if (ret) {
|
||||
pr_err("of_platform_populate failed: %d\n", ret);
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
static const char * const bcm2835_compat[] = {
|
||||
"brcm,bcm2835",
|
||||
NULL
|
||||
};
|
||||
|
||||
DT_MACHINE_START(BCM2835, "BCM2835")
|
||||
.map_io = bcm2835_map_io,
|
||||
.init_irq = bcm2835_init_irq,
|
||||
.handle_irq = bcm2835_handle_irq,
|
||||
.init_machine = bcm2835_init,
|
||||
.timer = &bcm2835_timer,
|
||||
.dt_compat = bcm2835_compat
|
||||
MACHINE_END
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Stephen Warren
|
||||
*
|
||||
* Derived from code:
|
||||
* Copyright (C) 2010 Broadcom
|
||||
*
|
||||
* 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_BCM2835_BCM2835_SOC_H__
|
||||
#define __MACH_BCM2835_BCM2835_SOC_H__
|
||||
|
||||
#include <asm/sizes.h>
|
||||
|
||||
#define BCM2835_PERIPH_PHYS 0x20000000
|
||||
#define BCM2835_PERIPH_VIRT 0xf0000000
|
||||
#define BCM2835_PERIPH_SIZE SZ_16M
|
||||
#define BCM2835_DEBUG_PHYS 0x20201000
|
||||
#define BCM2835_DEBUG_VIRT 0xf0201000
|
||||
|
||||
#endif
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Debugging macro include header
|
||||
*
|
||||
* Copyright (C) 2010 Broadcom
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <mach/bcm2835_soc.h>
|
||||
|
||||
.macro addruart, rp, rv, tmp
|
||||
ldr \rp, =BCM2835_DEBUG_PHYS
|
||||
ldr \rv, =BCM2835_DEBUG_VIRT
|
||||
.endm
|
||||
|
||||
#include <asm/hardware/debug-pl01x.S>
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* BCM2835 system clock frequency
|
||||
*
|
||||
* Copyright (C) 2010 Broadcom
|
||||
*
|
||||
* 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 __ASM_ARCH_TIMEX_H
|
||||
#define __ASM_ARCH_TIMEX_H
|
||||
|
||||
#define CLOCK_TICK_RATE (1000000)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (C) 2010 Broadcom
|
||||
* Copyright (C) 2003 ARM Limited
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/amba/serial.h>
|
||||
#include <mach/bcm2835_soc.h>
|
||||
|
||||
#define UART0_BASE BCM2835_DEBUG_PHYS
|
||||
|
||||
#define BCM2835_UART_DR IOMEM(UART0_BASE + UART01x_DR)
|
||||
#define BCM2835_UART_FR IOMEM(UART0_BASE + UART01x_FR)
|
||||
#define BCM2835_UART_CR IOMEM(UART0_BASE + UART011_CR)
|
||||
|
||||
static inline void putc(int c)
|
||||
{
|
||||
while (__raw_readl(BCM2835_UART_FR) & UART01x_FR_TXFF)
|
||||
barrier();
|
||||
|
||||
__raw_writel(c, BCM2835_UART_DR);
|
||||
}
|
||||
|
||||
static inline void flush(void)
|
||||
{
|
||||
int fr;
|
||||
|
||||
do {
|
||||
fr = __raw_readl(BCM2835_UART_FR);
|
||||
barrier();
|
||||
} while ((fr & (UART011_FR_TXFE | UART01x_FR_BUSY)) != UART011_FR_TXFE);
|
||||
}
|
||||
|
||||
#define arch_decomp_setup()
|
||||
#define arch_decomp_wdog()
|
|
@ -62,8 +62,8 @@ enum mx35_clks {
|
|||
kpp_gate, mlb_gate, mshc_gate, owire_gate, pwm_gate, rngc_gate,
|
||||
rtc_gate, rtic_gate, scc_gate, sdma_gate, spba_gate, spdif_gate,
|
||||
ssi1_gate, ssi2_gate, uart1_gate, uart2_gate, uart3_gate, usbotg_gate,
|
||||
wdog_gate, max_gate, admux_gate, csi_gate, iim_gate, gpu2d_gate,
|
||||
clk_max
|
||||
wdog_gate, max_gate, admux_gate, csi_gate, csi_div, csi_sel, iim_gate,
|
||||
gpu2d_gate, clk_max
|
||||
};
|
||||
|
||||
static struct clk *clk[clk_max];
|
||||
|
@ -142,6 +142,9 @@ int __init mx35_clocks_init()
|
|||
|
||||
clk[nfc_div] = imx_clk_divider("nfc_div", "ahb", base + MX35_CCM_PDR4, 28, 4);
|
||||
|
||||
clk[csi_sel] = imx_clk_mux("csi_sel", base + MX35_CCM_PDR2, 7, 1, std_sel, ARRAY_SIZE(std_sel));
|
||||
clk[csi_div] = imx_clk_divider("csi_div", "csi_sel", base + MX35_CCM_PDR2, 16, 6);
|
||||
|
||||
clk[asrc_gate] = imx_clk_gate2("asrc_gate", "ipg", base + MX35_CCM_CGR0, 0);
|
||||
clk[pata_gate] = imx_clk_gate2("pata_gate", "ipg", base + MX35_CCM_CGR0, 2);
|
||||
clk[audmux_gate] = imx_clk_gate2("audmux_gate", "ipg", base + MX35_CCM_CGR0, 4);
|
||||
|
@ -192,7 +195,7 @@ int __init mx35_clocks_init()
|
|||
clk[max_gate] = imx_clk_gate2("max_gate", "dummy", base + MX35_CCM_CGR2, 26);
|
||||
clk[admux_gate] = imx_clk_gate2("admux_gate", "ipg", base + MX35_CCM_CGR2, 30);
|
||||
|
||||
clk[csi_gate] = imx_clk_gate2("csi_gate", "ipg", base + MX35_CCM_CGR3, 0);
|
||||
clk[csi_gate] = imx_clk_gate2("csi_gate", "csi_div", base + MX35_CCM_CGR3, 0);
|
||||
clk[iim_gate] = imx_clk_gate2("iim_gate", "ipg", base + MX35_CCM_CGR3, 2);
|
||||
clk[gpu2d_gate] = imx_clk_gate2("gpu2d_gate", "ahb", base + MX35_CCM_CGR3, 4);
|
||||
|
||||
|
@ -228,6 +231,7 @@ int __init mx35_clocks_init()
|
|||
clk_register_clkdev(clk[i2c3_gate], NULL, "imx-i2c.2");
|
||||
clk_register_clkdev(clk[ipu_gate], NULL, "ipu-core");
|
||||
clk_register_clkdev(clk[ipu_gate], NULL, "mx3_sdc_fb");
|
||||
clk_register_clkdev(clk[kpp_gate], NULL, "imx-keypad");
|
||||
clk_register_clkdev(clk[owire_gate], NULL, "mxc_w1");
|
||||
clk_register_clkdev(clk[sdma_gate], NULL, "imx35-sdma");
|
||||
clk_register_clkdev(clk[ssi1_gate], NULL, "imx-ssi.0");
|
||||
|
@ -253,6 +257,7 @@ int __init mx35_clocks_init()
|
|||
clk_register_clkdev(clk[usbotg_gate], "ahb", "fsl-usb2-udc");
|
||||
clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0");
|
||||
clk_register_clkdev(clk[nfc_div], NULL, "mxc_nand.0");
|
||||
clk_register_clkdev(clk[csi_gate], NULL, "mx3-camera.0");
|
||||
|
||||
clk_prepare_enable(clk[spba_gate]);
|
||||
clk_prepare_enable(clk[gpio1_gate]);
|
||||
|
|
|
@ -49,6 +49,7 @@ static const char *mx53_tve_ext_sel[] = { "pll4_sw", "ckih1", };
|
|||
static const char *tve_sel[] = { "tve_pred", "tve_ext_sel", };
|
||||
static const char *ipu_sel[] = { "axi_a", "axi_b", "emi_slow_gate", "ahb", };
|
||||
static const char *vpu_sel[] = { "axi_a", "axi_b", "emi_slow_gate", "ahb", };
|
||||
static const char *mx53_can_sel[] = { "ipg", "ckih1", "ckih2", "lp_apm", };
|
||||
|
||||
enum imx5_clks {
|
||||
dummy, ckil, osc, ckih1, ckih2, ahb, ipg, axi_a, axi_b, uart_pred,
|
||||
|
@ -82,6 +83,7 @@ enum imx5_clks {
|
|||
ssi_ext1_podf, ssi_ext2_pred, ssi_ext2_podf, ssi1_root_gate,
|
||||
ssi2_root_gate, ssi3_root_gate, ssi_ext1_gate, ssi_ext2_gate,
|
||||
epit1_ipg_gate, epit1_hf_gate, epit2_ipg_gate, epit2_hf_gate,
|
||||
can_sel, can1_serial_gate, can1_ipg_gate,
|
||||
clk_max
|
||||
};
|
||||
|
||||
|
@ -421,8 +423,12 @@ int __init mx53_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,
|
|||
clk[esdhc4_per_gate] = imx_clk_gate2("esdhc4_per_gate", "esdhc_d_sel", MXC_CCM_CCGR3, 14);
|
||||
clk[usb_phy1_gate] = imx_clk_gate2("usb_phy1_gate", "usb_phy_sel", MXC_CCM_CCGR4, 10);
|
||||
clk[usb_phy2_gate] = imx_clk_gate2("usb_phy2_gate", "usb_phy_sel", MXC_CCM_CCGR4, 12);
|
||||
clk[can2_serial_gate] = imx_clk_gate2("can2_serial_gate", "ipg", MXC_CCM_CCGR4, 6);
|
||||
clk[can2_ipg_gate] = imx_clk_gate2("can2_ipg_gate", "ipg", MXC_CCM_CCGR4, 8);
|
||||
clk[can_sel] = imx_clk_mux("can_sel", MXC_CCM_CSCMR2, 6, 2,
|
||||
mx53_can_sel, ARRAY_SIZE(mx53_can_sel));
|
||||
clk[can1_serial_gate] = imx_clk_gate2("can1_serial_gate", "can_sel", MXC_CCM_CCGR6, 22);
|
||||
clk[can1_ipg_gate] = imx_clk_gate2("can1_ipg_gate", "ipg", MXC_CCM_CCGR6, 20);
|
||||
clk[can2_serial_gate] = imx_clk_gate2("can2_serial_gate", "can_sel", MXC_CCM_CCGR4, 8);
|
||||
clk[can2_ipg_gate] = imx_clk_gate2("can2_ipg_gate", "ipg", MXC_CCM_CCGR4, 6);
|
||||
clk[i2c3_gate] = imx_clk_gate2("i2c3_gate", "per_root", MXC_CCM_CCGR1, 22);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(clk); i++)
|
||||
|
@ -455,6 +461,10 @@ int __init mx53_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,
|
|||
clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "63fcc000.ssi");
|
||||
clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "50014000.ssi");
|
||||
clk_register_clkdev(clk[ssi3_ipg_gate], NULL, "63fd0000.ssi");
|
||||
clk_register_clkdev(clk[can1_ipg_gate], "ipg", "53fc8000.can");
|
||||
clk_register_clkdev(clk[can1_serial_gate], "per", "53fc8000.can");
|
||||
clk_register_clkdev(clk[can2_ipg_gate], "ipg", "53fcc000.can");
|
||||
clk_register_clkdev(clk[can2_serial_gate], "per", "53fcc000.can");
|
||||
|
||||
/* set SDHC root clock to 200MHZ*/
|
||||
clk_set_rate(clk[esdhc_a_podf], 200000000);
|
||||
|
|
|
@ -283,21 +283,25 @@ static int lpc32xx_set_irq_type(struct irq_data *d, unsigned int type)
|
|||
case IRQ_TYPE_EDGE_RISING:
|
||||
/* Rising edge sensitive */
|
||||
__lpc32xx_set_irq_type(d->hwirq, 1, 1);
|
||||
__irq_set_handler_locked(d->hwirq, handle_edge_irq);
|
||||
break;
|
||||
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
/* Falling edge sensitive */
|
||||
__lpc32xx_set_irq_type(d->hwirq, 0, 1);
|
||||
__irq_set_handler_locked(d->hwirq, handle_edge_irq);
|
||||
break;
|
||||
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
/* Low level sensitive */
|
||||
__lpc32xx_set_irq_type(d->hwirq, 0, 0);
|
||||
__irq_set_handler_locked(d->hwirq, handle_level_irq);
|
||||
break;
|
||||
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
/* High level sensitive */
|
||||
__lpc32xx_set_irq_type(d->hwirq, 1, 0);
|
||||
__irq_set_handler_locked(d->hwirq, handle_level_irq);
|
||||
break;
|
||||
|
||||
/* Other modes are not supported */
|
||||
|
@ -305,9 +309,6 @@ static int lpc32xx_set_irq_type(struct irq_data *d, unsigned int type)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Ok to use the level handler for all types */
|
||||
irq_set_handler(d->hwirq, handle_level_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/mtd/lpc32xx_slc.h>
|
||||
#include <linux/mtd/lpc32xx_mlc.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
@ -223,6 +225,14 @@ static struct mmci_platform_data lpc32xx_mmci_data = {
|
|||
* gather, and the MMCI driver doesn't do it this way */
|
||||
};
|
||||
|
||||
static struct lpc32xx_slc_platform_data lpc32xx_slc_data = {
|
||||
.dma_filter = pl08x_filter_id,
|
||||
};
|
||||
|
||||
static struct lpc32xx_mlc_platform_data lpc32xx_mlc_data = {
|
||||
.dma_filter = pl08x_filter_id,
|
||||
};
|
||||
|
||||
static const struct of_dev_auxdata lpc32xx_auxdata_lookup[] __initconst = {
|
||||
OF_DEV_AUXDATA("arm,pl022", 0x20084000, "dev:ssp0", &lpc32xx_ssp0_data),
|
||||
OF_DEV_AUXDATA("arm,pl022", 0x2008C000, "dev:ssp1", &lpc32xx_ssp1_data),
|
||||
|
@ -230,6 +240,10 @@ static const struct of_dev_auxdata lpc32xx_auxdata_lookup[] __initconst = {
|
|||
OF_DEV_AUXDATA("arm,pl080", 0x31000000, "pl08xdmac", &pl08x_pd),
|
||||
OF_DEV_AUXDATA("arm,pl18x", 0x20098000, "20098000.sd",
|
||||
&lpc32xx_mmci_data),
|
||||
OF_DEV_AUXDATA("nxp,lpc3220-slc", 0x20020000, "20020000.flash",
|
||||
&lpc32xx_slc_data),
|
||||
OF_DEV_AUXDATA("nxp,lpc3220-mlc", 0x200a8000, "200a8000.flash",
|
||||
&lpc32xx_mlc_data),
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -253,12 +267,6 @@ static void __init lpc3250_machine_init(void)
|
|||
|
||||
of_platform_populate(NULL, of_default_bus_match_table,
|
||||
lpc32xx_auxdata_lookup, NULL);
|
||||
|
||||
/* Register GPIOs used on this board */
|
||||
if (gpio_request(MMC_PWR_ENABLE_GPIO, "mmc_power_en"))
|
||||
pr_err("Error requesting gpio %u", MMC_PWR_ENABLE_GPIO);
|
||||
else if (gpio_direction_output(MMC_PWR_ENABLE_GPIO, 1))
|
||||
pr_err("Error setting gpio %u to output", MMC_PWR_ENABLE_GPIO);
|
||||
}
|
||||
|
||||
static char const *lpc32xx_dt_compat[] __initdata = {
|
||||
|
|
|
@ -174,6 +174,7 @@ obj-$(CONFIG_SOC_OMAP2430) += omap_hwmod_2430_data.o
|
|||
obj-$(CONFIG_ARCH_OMAP3) += omap_hwmod_2xxx_3xxx_ipblock_data.o
|
||||
obj-$(CONFIG_ARCH_OMAP3) += omap_hwmod_2xxx_3xxx_interconnect_data.o
|
||||
obj-$(CONFIG_ARCH_OMAP3) += omap_hwmod_3xxx_data.o
|
||||
obj-$(CONFIG_SOC_AM33XX) += omap_hwmod_33xx_data.o
|
||||
obj-$(CONFIG_ARCH_OMAP4) += omap_hwmod_44xx_data.o
|
||||
|
||||
# EMU peripherals
|
||||
|
|
|
@ -211,7 +211,7 @@ void omap2_init_dpll_parent(struct clk *clk)
|
|||
if (v == OMAP3XXX_EN_DPLL_LPBYPASS ||
|
||||
v == OMAP3XXX_EN_DPLL_FRBYPASS)
|
||||
clk_reparent(clk, dd->clk_bypass);
|
||||
} else if (cpu_is_omap44xx()) {
|
||||
} else if (soc_is_am33xx() || cpu_is_omap44xx()) {
|
||||
if (v == OMAP4XXX_EN_DPLL_LPBYPASS ||
|
||||
v == OMAP4XXX_EN_DPLL_FRBYPASS ||
|
||||
v == OMAP4XXX_EN_DPLL_MNBYPASS)
|
||||
|
@ -257,7 +257,7 @@ u32 omap2_get_dpll_rate(struct clk *clk)
|
|||
if (v == OMAP3XXX_EN_DPLL_LPBYPASS ||
|
||||
v == OMAP3XXX_EN_DPLL_FRBYPASS)
|
||||
return dd->clk_bypass->rate;
|
||||
} else if (cpu_is_omap44xx()) {
|
||||
} else if (soc_is_am33xx() || cpu_is_omap44xx()) {
|
||||
if (v == OMAP4XXX_EN_DPLL_LPBYPASS ||
|
||||
v == OMAP4XXX_EN_DPLL_FRBYPASS ||
|
||||
v == OMAP4XXX_EN_DPLL_MNBYPASS)
|
||||
|
|
|
@ -1027,7 +1027,9 @@ static struct omap_clk am33xx_clks[] = {
|
|||
CLK(NULL, "cefuse_fck", &cefuse_fck, CK_AM33XX),
|
||||
CLK(NULL, "clkdiv32k_ick", &clkdiv32k_ick, CK_AM33XX),
|
||||
CLK(NULL, "dcan0_fck", &dcan0_fck, CK_AM33XX),
|
||||
CLK("481cc000.d_can", NULL, &dcan0_fck, CK_AM33XX),
|
||||
CLK(NULL, "dcan1_fck", &dcan1_fck, CK_AM33XX),
|
||||
CLK("481d0000.d_can", NULL, &dcan1_fck, CK_AM33XX),
|
||||
CLK(NULL, "debugss_ick", &debugss_ick, CK_AM33XX),
|
||||
CLK(NULL, "pruss_ocp_gclk", &pruss_ocp_gclk, CK_AM33XX),
|
||||
CLK("davinci-mcasp.0", NULL, &mcasp0_fck, CK_AM33XX),
|
||||
|
|
|
@ -311,7 +311,7 @@ static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel)
|
|||
* Set jitter correction. No jitter correction for OMAP4 and 3630
|
||||
* since freqsel field is no longer present
|
||||
*/
|
||||
if (!cpu_is_omap44xx() && !cpu_is_omap3630()) {
|
||||
if (!soc_is_am33xx() && !cpu_is_omap44xx() && !cpu_is_omap3630()) {
|
||||
v = __raw_readl(dd->control_reg);
|
||||
v &= ~dd->freqsel_mask;
|
||||
v |= freqsel << __ffs(dd->freqsel_mask);
|
||||
|
@ -471,7 +471,7 @@ int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate)
|
|||
return -EINVAL;
|
||||
|
||||
/* No freqsel on OMAP4 and OMAP3630 */
|
||||
if (!cpu_is_omap44xx() && !cpu_is_omap3630()) {
|
||||
if (!soc_is_am33xx() && !cpu_is_omap44xx() && !cpu_is_omap3630()) {
|
||||
freqsel = _omap3_dpll_compute_freqsel(clk,
|
||||
dd->last_rounded_n);
|
||||
if (!freqsel)
|
||||
|
|
|
@ -524,6 +524,8 @@ void __init am33xx_init_early(void)
|
|||
am33xx_voltagedomains_init();
|
||||
am33xx_powerdomains_init();
|
||||
am33xx_clockdomains_init();
|
||||
am33xx_hwmod_init();
|
||||
omap_hwmod_init_postsetup();
|
||||
am33xx_clk_init();
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -149,8 +149,10 @@
|
|||
#include "powerdomain.h"
|
||||
#include "cm2xxx_3xxx.h"
|
||||
#include "cminst44xx.h"
|
||||
#include "cm33xx.h"
|
||||
#include "prm2xxx_3xxx.h"
|
||||
#include "prm44xx.h"
|
||||
#include "prm33xx.h"
|
||||
#include "prminst44xx.h"
|
||||
#include "mux.h"
|
||||
#include "pm.h"
|
||||
|
@ -867,6 +869,26 @@ static void _omap4_enable_module(struct omap_hwmod *oh)
|
|||
oh->prcm.omap4.clkctrl_offs);
|
||||
}
|
||||
|
||||
/**
|
||||
* _am33xx_enable_module - enable CLKCTRL modulemode on AM33XX
|
||||
* @oh: struct omap_hwmod *
|
||||
*
|
||||
* Enables the PRCM module mode related to the hwmod @oh.
|
||||
* No return value.
|
||||
*/
|
||||
static void _am33xx_enable_module(struct omap_hwmod *oh)
|
||||
{
|
||||
if (!oh->clkdm || !oh->prcm.omap4.modulemode)
|
||||
return;
|
||||
|
||||
pr_debug("omap_hwmod: %s: %s: %d\n",
|
||||
oh->name, __func__, oh->prcm.omap4.modulemode);
|
||||
|
||||
am33xx_cm_module_enable(oh->prcm.omap4.modulemode, oh->clkdm->cm_inst,
|
||||
oh->clkdm->clkdm_offs,
|
||||
oh->prcm.omap4.clkctrl_offs);
|
||||
}
|
||||
|
||||
/**
|
||||
* _omap4_wait_target_disable - wait for a module to be disabled on OMAP4
|
||||
* @oh: struct omap_hwmod *
|
||||
|
@ -893,6 +915,31 @@ static int _omap4_wait_target_disable(struct omap_hwmod *oh)
|
|||
oh->prcm.omap4.clkctrl_offs);
|
||||
}
|
||||
|
||||
/**
|
||||
* _am33xx_wait_target_disable - wait for a module to be disabled on AM33XX
|
||||
* @oh: struct omap_hwmod *
|
||||
*
|
||||
* Wait for a module @oh to enter slave idle. Returns 0 if the module
|
||||
* does not have an IDLEST bit or if the module successfully enters
|
||||
* slave idle; otherwise, pass along the return value of the
|
||||
* appropriate *_cm*_wait_module_idle() function.
|
||||
*/
|
||||
static int _am33xx_wait_target_disable(struct omap_hwmod *oh)
|
||||
{
|
||||
if (!oh)
|
||||
return -EINVAL;
|
||||
|
||||
if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
|
||||
return 0;
|
||||
|
||||
if (oh->flags & HWMOD_NO_IDLEST)
|
||||
return 0;
|
||||
|
||||
return am33xx_cm_wait_module_idle(oh->clkdm->cm_inst,
|
||||
oh->clkdm->clkdm_offs,
|
||||
oh->prcm.omap4.clkctrl_offs);
|
||||
}
|
||||
|
||||
/**
|
||||
* _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh
|
||||
* @oh: struct omap_hwmod *oh
|
||||
|
@ -1613,6 +1660,36 @@ static int _omap4_disable_module(struct omap_hwmod *oh)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* _am33xx_disable_module - enable CLKCTRL modulemode on AM33XX
|
||||
* @oh: struct omap_hwmod *
|
||||
*
|
||||
* Disable the PRCM module mode related to the hwmod @oh.
|
||||
* Return EINVAL if the modulemode is not supported and 0 in case of success.
|
||||
*/
|
||||
static int _am33xx_disable_module(struct omap_hwmod *oh)
|
||||
{
|
||||
int v;
|
||||
|
||||
if (!oh->clkdm || !oh->prcm.omap4.modulemode)
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__);
|
||||
|
||||
am33xx_cm_module_disable(oh->clkdm->cm_inst, oh->clkdm->clkdm_offs,
|
||||
oh->prcm.omap4.clkctrl_offs);
|
||||
|
||||
if (_are_any_hardreset_lines_asserted(oh))
|
||||
return 0;
|
||||
|
||||
v = _am33xx_wait_target_disable(oh);
|
||||
if (v)
|
||||
pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
|
||||
oh->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit
|
||||
* @oh: struct omap_hwmod *
|
||||
|
@ -2548,6 +2625,33 @@ static int _omap4_wait_target_ready(struct omap_hwmod *oh)
|
|||
oh->prcm.omap4.clkctrl_offs);
|
||||
}
|
||||
|
||||
/**
|
||||
* _am33xx_wait_target_ready - wait for a module to leave slave idle
|
||||
* @oh: struct omap_hwmod *
|
||||
*
|
||||
* Wait for a module @oh to leave slave idle. Returns 0 if the module
|
||||
* does not have an IDLEST bit or if the module successfully leaves
|
||||
* slave idle; otherwise, pass along the return value of the
|
||||
* appropriate *_cm*_wait_module_ready() function.
|
||||
*/
|
||||
static int _am33xx_wait_target_ready(struct omap_hwmod *oh)
|
||||
{
|
||||
if (!oh || !oh->clkdm)
|
||||
return -EINVAL;
|
||||
|
||||
if (oh->flags & HWMOD_NO_IDLEST)
|
||||
return 0;
|
||||
|
||||
if (!_find_mpu_rt_port(oh))
|
||||
return 0;
|
||||
|
||||
/* XXX check module SIDLEMODE, hardreset status */
|
||||
|
||||
return am33xx_cm_wait_module_ready(oh->clkdm->cm_inst,
|
||||
oh->clkdm->clkdm_offs,
|
||||
oh->prcm.omap4.clkctrl_offs);
|
||||
}
|
||||
|
||||
/**
|
||||
* _omap2_assert_hardreset - call OMAP2 PRM hardreset fn with hwmod args
|
||||
* @oh: struct omap_hwmod * to assert hardreset
|
||||
|
@ -2679,6 +2783,72 @@ static int _omap4_is_hardreset_asserted(struct omap_hwmod *oh,
|
|||
oh->prcm.omap4.rstctrl_offs);
|
||||
}
|
||||
|
||||
/**
|
||||
* _am33xx_assert_hardreset - call AM33XX PRM hardreset fn with hwmod args
|
||||
* @oh: struct omap_hwmod * to assert hardreset
|
||||
* @ohri: hardreset line data
|
||||
*
|
||||
* Call am33xx_prminst_assert_hardreset() with parameters extracted
|
||||
* from the hwmod @oh and the hardreset line data @ohri. Only
|
||||
* intended for use as an soc_ops function pointer. Passes along the
|
||||
* return value from am33xx_prminst_assert_hardreset(). XXX This
|
||||
* function is scheduled for removal when the PRM code is moved into
|
||||
* drivers/.
|
||||
*/
|
||||
static int _am33xx_assert_hardreset(struct omap_hwmod *oh,
|
||||
struct omap_hwmod_rst_info *ohri)
|
||||
|
||||
{
|
||||
return am33xx_prm_assert_hardreset(ohri->rst_shift,
|
||||
oh->clkdm->pwrdm.ptr->prcm_offs,
|
||||
oh->prcm.omap4.rstctrl_offs);
|
||||
}
|
||||
|
||||
/**
|
||||
* _am33xx_deassert_hardreset - call AM33XX PRM hardreset fn with hwmod args
|
||||
* @oh: struct omap_hwmod * to deassert hardreset
|
||||
* @ohri: hardreset line data
|
||||
*
|
||||
* Call am33xx_prminst_deassert_hardreset() with parameters extracted
|
||||
* from the hwmod @oh and the hardreset line data @ohri. Only
|
||||
* intended for use as an soc_ops function pointer. Passes along the
|
||||
* return value from am33xx_prminst_deassert_hardreset(). XXX This
|
||||
* function is scheduled for removal when the PRM code is moved into
|
||||
* drivers/.
|
||||
*/
|
||||
static int _am33xx_deassert_hardreset(struct omap_hwmod *oh,
|
||||
struct omap_hwmod_rst_info *ohri)
|
||||
{
|
||||
if (ohri->st_shift)
|
||||
pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n",
|
||||
oh->name, ohri->name);
|
||||
|
||||
return am33xx_prm_deassert_hardreset(ohri->rst_shift,
|
||||
oh->clkdm->pwrdm.ptr->prcm_offs,
|
||||
oh->prcm.omap4.rstctrl_offs,
|
||||
oh->prcm.omap4.rstst_offs);
|
||||
}
|
||||
|
||||
/**
|
||||
* _am33xx_is_hardreset_asserted - call AM33XX PRM hardreset fn with hwmod args
|
||||
* @oh: struct omap_hwmod * to test hardreset
|
||||
* @ohri: hardreset line data
|
||||
*
|
||||
* Call am33xx_prminst_is_hardreset_asserted() with parameters
|
||||
* extracted from the hwmod @oh and the hardreset line data @ohri.
|
||||
* Only intended for use as an soc_ops function pointer. Passes along
|
||||
* the return value from am33xx_prminst_is_hardreset_asserted(). XXX
|
||||
* This function is scheduled for removal when the PRM code is moved
|
||||
* into drivers/.
|
||||
*/
|
||||
static int _am33xx_is_hardreset_asserted(struct omap_hwmod *oh,
|
||||
struct omap_hwmod_rst_info *ohri)
|
||||
{
|
||||
return am33xx_prm_is_hardreset_asserted(ohri->rst_shift,
|
||||
oh->clkdm->pwrdm.ptr->prcm_offs,
|
||||
oh->prcm.omap4.rstctrl_offs);
|
||||
}
|
||||
|
||||
/* Public functions */
|
||||
|
||||
u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs)
|
||||
|
@ -3705,6 +3875,14 @@ void __init omap_hwmod_init(void)
|
|||
soc_ops.deassert_hardreset = _omap4_deassert_hardreset;
|
||||
soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted;
|
||||
soc_ops.init_clkdm = _init_clkdm;
|
||||
} else if (soc_is_am33xx()) {
|
||||
soc_ops.enable_module = _am33xx_enable_module;
|
||||
soc_ops.disable_module = _am33xx_disable_module;
|
||||
soc_ops.wait_target_ready = _am33xx_wait_target_ready;
|
||||
soc_ops.assert_hardreset = _am33xx_assert_hardreset;
|
||||
soc_ops.deassert_hardreset = _am33xx_deassert_hardreset;
|
||||
soc_ops.is_hardreset_asserted = _am33xx_is_hardreset_asserted;
|
||||
soc_ops.init_clkdm = _init_clkdm;
|
||||
} else {
|
||||
WARN(1, "omap_hwmod: unknown SoC type\n");
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -763,6 +763,13 @@ static void __init kzm_init(void)
|
|||
platform_add_devices(kzm_devices, ARRAY_SIZE(kzm_devices));
|
||||
}
|
||||
|
||||
static void kzm9g_restart(char mode, const char *cmd)
|
||||
{
|
||||
#define RESCNT2 0xe6188020
|
||||
/* Do soft power on reset */
|
||||
writel((1 << 31), RESCNT2);
|
||||
}
|
||||
|
||||
static const char *kzm9g_boards_compat_dt[] __initdata = {
|
||||
"renesas,kzm9g",
|
||||
NULL,
|
||||
|
@ -777,5 +784,6 @@ DT_MACHINE_START(KZM9G_DT, "kzm9g")
|
|||
.init_machine = kzm_init,
|
||||
.init_late = shmobile_init_late,
|
||||
.timer = &shmobile_timer,
|
||||
.restart = kzm9g_restart,
|
||||
.dt_compat = kzm9g_boards_compat_dt,
|
||||
MACHINE_END
|
||||
|
|
|
@ -86,11 +86,16 @@ static struct clk div4_clks[DIV4_NR] = {
|
|||
0x0300, CLK_ENABLE_ON_INIT),
|
||||
};
|
||||
|
||||
enum { MSTP026, MSTP025, MSTP024, MSTP023, MSTP022, MSTP021,
|
||||
enum { MSTP323, MSTP322, MSTP321, MSTP320,
|
||||
MSTP026, MSTP025, MSTP024, MSTP023, MSTP022, MSTP021,
|
||||
MSTP016, MSTP015, MSTP014,
|
||||
MSTP_NR };
|
||||
|
||||
static struct clk mstp_clks[MSTP_NR] = {
|
||||
[MSTP323] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 23, 0), /* SDHI0 */
|
||||
[MSTP322] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 22, 0), /* SDHI1 */
|
||||
[MSTP321] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 21, 0), /* SDHI2 */
|
||||
[MSTP320] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 20, 0), /* SDHI3 */
|
||||
[MSTP026] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 26, 0), /* SCIF0 */
|
||||
[MSTP025] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 25, 0), /* SCIF1 */
|
||||
[MSTP024] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 24, 0), /* SCIF2 */
|
||||
|
@ -149,6 +154,10 @@ static struct clk_lookup lookups[] = {
|
|||
CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP023]), /* SCIF3 */
|
||||
CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP022]), /* SCIF4 */
|
||||
CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP021]), /* SCIF6 */
|
||||
CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP323]), /* SDHI0 */
|
||||
CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP322]), /* SDHI1 */
|
||||
CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP321]), /* SDHI2 */
|
||||
CLKDEV_DEV_ID("sh_mobile_sdhi.3", &mstp_clks[MSTP320]), /* SDHI3 */
|
||||
};
|
||||
|
||||
void __init r8a7779_clock_init(void)
|
||||
|
|
|
@ -356,6 +356,26 @@ static struct platform_device gio4_device = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct resource pmu_resources[] = {
|
||||
[0] = {
|
||||
.start = 152,
|
||||
.end = 152,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[1] = {
|
||||
.start = 153,
|
||||
.end = 153,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device pmu_device = {
|
||||
.name = "arm-pmu",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(pmu_resources),
|
||||
.resource = pmu_resources,
|
||||
};
|
||||
|
||||
static struct platform_device *emev2_early_devices[] __initdata = {
|
||||
&uart0_device,
|
||||
&uart1_device,
|
||||
|
@ -370,6 +390,7 @@ static struct platform_device *emev2_late_devices[] __initdata = {
|
|||
&gio2_device,
|
||||
&gio3_device,
|
||||
&gio4_device,
|
||||
&pmu_device,
|
||||
};
|
||||
|
||||
void __init emev2_add_standard_devices(void)
|
||||
|
|
|
@ -734,6 +734,26 @@ static struct platform_device mpdma0_device = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct resource pmu_resources[] = {
|
||||
[0] = {
|
||||
.start = gic_spi(55),
|
||||
.end = gic_spi(55),
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[1] = {
|
||||
.start = gic_spi(56),
|
||||
.end = gic_spi(56),
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device pmu_device = {
|
||||
.name = "arm-pmu",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(pmu_resources),
|
||||
.resource = pmu_resources,
|
||||
};
|
||||
|
||||
static struct platform_device *sh73a0_early_devices[] __initdata = {
|
||||
&scif0_device,
|
||||
&scif1_device,
|
||||
|
@ -757,6 +777,7 @@ static struct platform_device *sh73a0_late_devices[] __initdata = {
|
|||
&i2c4_device,
|
||||
&dma0_device,
|
||||
&mpdma0_device,
|
||||
&pmu_device,
|
||||
};
|
||||
|
||||
#define SRCR2 0xe61580b0
|
||||
|
|
|
@ -12,9 +12,13 @@ obj-y += powergate.o
|
|||
obj-y += apbio.o
|
||||
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
|
||||
obj-$(CONFIG_CPU_IDLE) += sleep.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_clocks.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks_data.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-t20.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks_data.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-t30.o
|
||||
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
|
||||
obj-$(CONFIG_SMP) += reset.o
|
||||
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
||||
|
|
|
@ -70,6 +70,7 @@ struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
|
|||
|
||||
static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {
|
||||
/* name parent rate enabled */
|
||||
{ "uarta", "pll_p", 216000000, true },
|
||||
{ "uartd", "pll_p", 216000000, true },
|
||||
{ "usbd", "clk_m", 12000000, false },
|
||||
{ "usb2", "clk_m", 12000000, false },
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
* Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Colin Cross <ccross@google.com>
|
||||
|
@ -19,8 +20,6 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -32,44 +31,38 @@
|
|||
|
||||
#include "board.h"
|
||||
#include "clock.h"
|
||||
#include "tegra_cpu_car.h"
|
||||
|
||||
/* Global data of Tegra CPU CAR ops */
|
||||
struct tegra_cpu_car_ops *tegra_cpu_car_ops;
|
||||
|
||||
/*
|
||||
* Locking:
|
||||
*
|
||||
* Each struct clk has a spinlock.
|
||||
*
|
||||
* To avoid AB-BA locking problems, locks must always be traversed from child
|
||||
* clock to parent clock. For example, when enabling a clock, the clock's lock
|
||||
* is taken, and then clk_enable is called on the parent, which take's the
|
||||
* parent clock's lock. There is one exceptions to this ordering: When dumping
|
||||
* the clock tree through debugfs. In this case, clk_lock_all is called,
|
||||
* which attemps to iterate through the entire list of clocks and take every
|
||||
* clock lock. If any call to spin_trylock fails, all locked clocks are
|
||||
* unlocked, and the process is retried. When all the locks are held,
|
||||
* the only clock operation that can be called is clk_get_rate_all_locked.
|
||||
*
|
||||
* Within a single clock, no clock operation can call another clock operation
|
||||
* on itself, except for clk_get_rate_locked and clk_set_rate_locked. Any
|
||||
* clock operation can call any other clock operation on any of it's possible
|
||||
* parents.
|
||||
*
|
||||
* An additional mutex, clock_list_lock, is used to protect the list of all
|
||||
* clocks.
|
||||
*
|
||||
* The clock operations must lock internally to protect against
|
||||
* read-modify-write on registers that are shared by multiple clocks
|
||||
*/
|
||||
static DEFINE_MUTEX(clock_list_lock);
|
||||
static LIST_HEAD(clocks);
|
||||
|
||||
void tegra_clk_add(struct clk *clk)
|
||||
{
|
||||
struct clk_tegra *c = to_clk_tegra(__clk_get_hw(clk));
|
||||
|
||||
mutex_lock(&clock_list_lock);
|
||||
list_add(&c->node, &clocks);
|
||||
mutex_unlock(&clock_list_lock);
|
||||
}
|
||||
|
||||
struct clk *tegra_get_clock_by_name(const char *name)
|
||||
{
|
||||
struct clk *c;
|
||||
struct clk_tegra *c;
|
||||
struct clk *ret = NULL;
|
||||
mutex_lock(&clock_list_lock);
|
||||
list_for_each_entry(c, &clocks, node) {
|
||||
if (strcmp(c->name, name) == 0) {
|
||||
ret = c;
|
||||
if (strcmp(__clk_get_name(c->hw.clk), name) == 0) {
|
||||
ret = c->hw.clk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -77,280 +70,36 @@ struct clk *tegra_get_clock_by_name(const char *name)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Must be called with c->spinlock held */
|
||||
static unsigned long clk_predict_rate_from_parent(struct clk *c, struct clk *p)
|
||||
{
|
||||
u64 rate;
|
||||
|
||||
rate = clk_get_rate(p);
|
||||
|
||||
if (c->mul != 0 && c->div != 0) {
|
||||
rate *= c->mul;
|
||||
rate += c->div - 1; /* round up */
|
||||
do_div(rate, c->div);
|
||||
}
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
/* Must be called with c->spinlock held */
|
||||
unsigned long clk_get_rate_locked(struct clk *c)
|
||||
{
|
||||
unsigned long rate;
|
||||
|
||||
if (c->parent)
|
||||
rate = clk_predict_rate_from_parent(c, c->parent);
|
||||
else
|
||||
rate = c->rate;
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
unsigned long clk_get_rate(struct clk *c)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long rate;
|
||||
|
||||
spin_lock_irqsave(&c->spinlock, flags);
|
||||
|
||||
rate = clk_get_rate_locked(c);
|
||||
|
||||
spin_unlock_irqrestore(&c->spinlock, flags);
|
||||
|
||||
return rate;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_get_rate);
|
||||
|
||||
int clk_reparent(struct clk *c, struct clk *parent)
|
||||
{
|
||||
c->parent = parent;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clk_init(struct clk *c)
|
||||
{
|
||||
spin_lock_init(&c->spinlock);
|
||||
|
||||
if (c->ops && c->ops->init)
|
||||
c->ops->init(c);
|
||||
|
||||
if (!c->ops || !c->ops->enable) {
|
||||
c->refcnt++;
|
||||
c->set = true;
|
||||
if (c->parent)
|
||||
c->state = c->parent->state;
|
||||
else
|
||||
c->state = ON;
|
||||
}
|
||||
|
||||
mutex_lock(&clock_list_lock);
|
||||
list_add(&c->node, &clocks);
|
||||
mutex_unlock(&clock_list_lock);
|
||||
}
|
||||
|
||||
int clk_enable(struct clk *c)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&c->spinlock, flags);
|
||||
|
||||
if (c->refcnt == 0) {
|
||||
if (c->parent) {
|
||||
ret = clk_enable(c->parent);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (c->ops && c->ops->enable) {
|
||||
ret = c->ops->enable(c);
|
||||
if (ret) {
|
||||
if (c->parent)
|
||||
clk_disable(c->parent);
|
||||
goto out;
|
||||
}
|
||||
c->state = ON;
|
||||
c->set = true;
|
||||
}
|
||||
}
|
||||
c->refcnt++;
|
||||
out:
|
||||
spin_unlock_irqrestore(&c->spinlock, flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_enable);
|
||||
|
||||
void clk_disable(struct clk *c)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&c->spinlock, flags);
|
||||
|
||||
if (c->refcnt == 0) {
|
||||
WARN(1, "Attempting to disable clock %s with refcnt 0", c->name);
|
||||
spin_unlock_irqrestore(&c->spinlock, flags);
|
||||
return;
|
||||
}
|
||||
if (c->refcnt == 1) {
|
||||
if (c->ops && c->ops->disable)
|
||||
c->ops->disable(c);
|
||||
|
||||
if (c->parent)
|
||||
clk_disable(c->parent);
|
||||
|
||||
c->state = OFF;
|
||||
}
|
||||
c->refcnt--;
|
||||
|
||||
spin_unlock_irqrestore(&c->spinlock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(clk_disable);
|
||||
|
||||
int clk_set_parent(struct clk *c, struct clk *parent)
|
||||
{
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
unsigned long new_rate;
|
||||
unsigned long old_rate;
|
||||
|
||||
spin_lock_irqsave(&c->spinlock, flags);
|
||||
|
||||
if (!c->ops || !c->ops->set_parent) {
|
||||
ret = -ENOSYS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
new_rate = clk_predict_rate_from_parent(c, parent);
|
||||
old_rate = clk_get_rate_locked(c);
|
||||
|
||||
ret = c->ops->set_parent(c, parent);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&c->spinlock, flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_set_parent);
|
||||
|
||||
struct clk *clk_get_parent(struct clk *c)
|
||||
{
|
||||
return c->parent;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_get_parent);
|
||||
|
||||
int clk_set_rate_locked(struct clk *c, unsigned long rate)
|
||||
{
|
||||
long new_rate;
|
||||
|
||||
if (!c->ops || !c->ops->set_rate)
|
||||
return -ENOSYS;
|
||||
|
||||
if (rate > c->max_rate)
|
||||
rate = c->max_rate;
|
||||
|
||||
if (c->ops && c->ops->round_rate) {
|
||||
new_rate = c->ops->round_rate(c, rate);
|
||||
|
||||
if (new_rate < 0)
|
||||
return new_rate;
|
||||
|
||||
rate = new_rate;
|
||||
}
|
||||
|
||||
return c->ops->set_rate(c, rate);
|
||||
}
|
||||
|
||||
int clk_set_rate(struct clk *c, unsigned long rate)
|
||||
{
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&c->spinlock, flags);
|
||||
|
||||
ret = clk_set_rate_locked(c, rate);
|
||||
|
||||
spin_unlock_irqrestore(&c->spinlock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_set_rate);
|
||||
|
||||
|
||||
/* Must be called with clocks lock and all indvidual clock locks held */
|
||||
unsigned long clk_get_rate_all_locked(struct clk *c)
|
||||
{
|
||||
u64 rate;
|
||||
int mul = 1;
|
||||
int div = 1;
|
||||
struct clk *p = c;
|
||||
|
||||
while (p) {
|
||||
c = p;
|
||||
if (c->mul != 0 && c->div != 0) {
|
||||
mul *= c->mul;
|
||||
div *= c->div;
|
||||
}
|
||||
p = c->parent;
|
||||
}
|
||||
|
||||
rate = c->rate;
|
||||
rate *= mul;
|
||||
do_div(rate, div);
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
long clk_round_rate(struct clk *c, unsigned long rate)
|
||||
{
|
||||
unsigned long flags;
|
||||
long ret;
|
||||
|
||||
spin_lock_irqsave(&c->spinlock, flags);
|
||||
|
||||
if (!c->ops || !c->ops->round_rate) {
|
||||
ret = -ENOSYS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rate > c->max_rate)
|
||||
rate = c->max_rate;
|
||||
|
||||
ret = c->ops->round_rate(c, rate);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&c->spinlock, flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_round_rate);
|
||||
|
||||
static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table)
|
||||
{
|
||||
struct clk *c;
|
||||
struct clk *p;
|
||||
struct clk *parent;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
c = tegra_get_clock_by_name(table->name);
|
||||
|
||||
if (!c) {
|
||||
pr_warning("Unable to initialize clock %s\n",
|
||||
pr_warn("Unable to initialize clock %s\n",
|
||||
table->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
parent = clk_get_parent(c);
|
||||
|
||||
if (table->parent) {
|
||||
p = tegra_get_clock_by_name(table->parent);
|
||||
if (!p) {
|
||||
pr_warning("Unable to find parent %s of clock %s\n",
|
||||
pr_warn("Unable to find parent %s of clock %s\n",
|
||||
table->parent, table->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (c->parent != p) {
|
||||
if (parent != p) {
|
||||
ret = clk_set_parent(c, p);
|
||||
if (ret) {
|
||||
pr_warning("Unable to set parent %s of clock %s: %d\n",
|
||||
pr_warn("Unable to set parent %s of clock %s: %d\n",
|
||||
table->parent, table->name, ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -360,16 +109,16 @@ static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table)
|
|||
if (table->rate && table->rate != clk_get_rate(c)) {
|
||||
ret = clk_set_rate(c, table->rate);
|
||||
if (ret) {
|
||||
pr_warning("Unable to set clock %s to rate %lu: %d\n",
|
||||
pr_warn("Unable to set clock %s to rate %lu: %d\n",
|
||||
table->name, table->rate, ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (table->enabled) {
|
||||
ret = clk_enable(c);
|
||||
ret = clk_prepare_enable(c);
|
||||
if (ret) {
|
||||
pr_warning("Unable to enable clock %s: %d\n",
|
||||
pr_warn("Unable to enable clock %s: %d\n",
|
||||
table->name, ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -383,19 +132,20 @@ void tegra_clk_init_from_table(struct tegra_clk_init_table *table)
|
|||
for (; table->name; table++)
|
||||
tegra_clk_init_one_from_table(table);
|
||||
}
|
||||
EXPORT_SYMBOL(tegra_clk_init_from_table);
|
||||
|
||||
void tegra_periph_reset_deassert(struct clk *c)
|
||||
{
|
||||
BUG_ON(!c->ops->reset);
|
||||
c->ops->reset(c, false);
|
||||
struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
|
||||
BUG_ON(!clk->reset);
|
||||
clk->reset(__clk_get_hw(c), false);
|
||||
}
|
||||
EXPORT_SYMBOL(tegra_periph_reset_deassert);
|
||||
|
||||
void tegra_periph_reset_assert(struct clk *c)
|
||||
{
|
||||
BUG_ON(!c->ops->reset);
|
||||
c->ops->reset(c, true);
|
||||
struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
|
||||
BUG_ON(!clk->reset);
|
||||
clk->reset(__clk_get_hw(c), true);
|
||||
}
|
||||
EXPORT_SYMBOL(tegra_periph_reset_assert);
|
||||
|
||||
|
@ -405,268 +155,14 @@ EXPORT_SYMBOL(tegra_periph_reset_assert);
|
|||
int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
|
||||
|
||||
spin_lock_irqsave(&c->spinlock, flags);
|
||||
|
||||
if (!c->ops || !c->ops->clk_cfg_ex) {
|
||||
if (!clk->clk_cfg_ex) {
|
||||
ret = -ENOSYS;
|
||||
goto out;
|
||||
}
|
||||
ret = c->ops->clk_cfg_ex(c, p, setting);
|
||||
ret = clk->clk_cfg_ex(__clk_get_hw(c), p, setting);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&c->spinlock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
static int __clk_lock_all_spinlocks(void)
|
||||
{
|
||||
struct clk *c;
|
||||
|
||||
list_for_each_entry(c, &clocks, node)
|
||||
if (!spin_trylock(&c->spinlock))
|
||||
goto unlock_spinlocks;
|
||||
|
||||
return 0;
|
||||
|
||||
unlock_spinlocks:
|
||||
list_for_each_entry_continue_reverse(c, &clocks, node)
|
||||
spin_unlock(&c->spinlock);
|
||||
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
static void __clk_unlock_all_spinlocks(void)
|
||||
{
|
||||
struct clk *c;
|
||||
|
||||
list_for_each_entry_reverse(c, &clocks, node)
|
||||
spin_unlock(&c->spinlock);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function retries until it can take all locks, and may take
|
||||
* an arbitrarily long time to complete.
|
||||
* Must be called with irqs enabled, returns with irqs disabled
|
||||
* Must be called with clock_list_lock held
|
||||
*/
|
||||
static void clk_lock_all(void)
|
||||
{
|
||||
int ret;
|
||||
retry:
|
||||
local_irq_disable();
|
||||
|
||||
ret = __clk_lock_all_spinlocks();
|
||||
if (ret)
|
||||
goto failed_spinlocks;
|
||||
|
||||
/* All locks taken successfully, return */
|
||||
return;
|
||||
|
||||
failed_spinlocks:
|
||||
local_irq_enable();
|
||||
yield();
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlocks all clocks after a clk_lock_all
|
||||
* Must be called with irqs disabled, returns with irqs enabled
|
||||
* Must be called with clock_list_lock held
|
||||
*/
|
||||
static void clk_unlock_all(void)
|
||||
{
|
||||
__clk_unlock_all_spinlocks();
|
||||
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
static struct dentry *clk_debugfs_root;
|
||||
|
||||
|
||||
static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)
|
||||
{
|
||||
struct clk *child;
|
||||
const char *state = "uninit";
|
||||
char div[8] = {0};
|
||||
|
||||
if (c->state == ON)
|
||||
state = "on";
|
||||
else if (c->state == OFF)
|
||||
state = "off";
|
||||
|
||||
if (c->mul != 0 && c->div != 0) {
|
||||
if (c->mul > c->div) {
|
||||
int mul = c->mul / c->div;
|
||||
int mul2 = (c->mul * 10 / c->div) % 10;
|
||||
int mul3 = (c->mul * 10) % c->div;
|
||||
if (mul2 == 0 && mul3 == 0)
|
||||
snprintf(div, sizeof(div), "x%d", mul);
|
||||
else if (mul3 == 0)
|
||||
snprintf(div, sizeof(div), "x%d.%d", mul, mul2);
|
||||
else
|
||||
snprintf(div, sizeof(div), "x%d.%d..", mul, mul2);
|
||||
} else {
|
||||
snprintf(div, sizeof(div), "%d%s", c->div / c->mul,
|
||||
(c->div % c->mul) ? ".5" : "");
|
||||
}
|
||||
}
|
||||
|
||||
seq_printf(s, "%*s%c%c%-*s %-6s %-3d %-8s %-10lu\n",
|
||||
level * 3 + 1, "",
|
||||
c->rate > c->max_rate ? '!' : ' ',
|
||||
!c->set ? '*' : ' ',
|
||||
30 - level * 3, c->name,
|
||||
state, c->refcnt, div, clk_get_rate_all_locked(c));
|
||||
|
||||
list_for_each_entry(child, &clocks, node) {
|
||||
if (child->parent != c)
|
||||
continue;
|
||||
|
||||
clock_tree_show_one(s, child, level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int clock_tree_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct clk *c;
|
||||
seq_printf(s, " clock state ref div rate\n");
|
||||
seq_printf(s, "--------------------------------------------------------------\n");
|
||||
|
||||
mutex_lock(&clock_list_lock);
|
||||
|
||||
clk_lock_all();
|
||||
|
||||
list_for_each_entry(c, &clocks, node)
|
||||
if (c->parent == NULL)
|
||||
clock_tree_show_one(s, c, 0);
|
||||
|
||||
clk_unlock_all();
|
||||
|
||||
mutex_unlock(&clock_list_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clock_tree_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, clock_tree_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations clock_tree_fops = {
|
||||
.open = clock_tree_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int possible_parents_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct clk *c = s->private;
|
||||
int i;
|
||||
|
||||
for (i = 0; c->inputs[i].input; i++) {
|
||||
char *first = (i == 0) ? "" : " ";
|
||||
seq_printf(s, "%s%s", first, c->inputs[i].input->name);
|
||||
}
|
||||
seq_printf(s, "\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int possible_parents_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, possible_parents_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations possible_parents_fops = {
|
||||
.open = possible_parents_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int clk_debugfs_register_one(struct clk *c)
|
||||
{
|
||||
struct dentry *d;
|
||||
|
||||
d = debugfs_create_dir(c->name, clk_debugfs_root);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
c->dent = d;
|
||||
|
||||
d = debugfs_create_u8("refcnt", S_IRUGO, c->dent, (u8 *)&c->refcnt);
|
||||
if (!d)
|
||||
goto err_out;
|
||||
|
||||
d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
|
||||
if (!d)
|
||||
goto err_out;
|
||||
|
||||
d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
|
||||
if (!d)
|
||||
goto err_out;
|
||||
|
||||
if (c->inputs) {
|
||||
d = debugfs_create_file("possible_parents", S_IRUGO, c->dent,
|
||||
c, &possible_parents_fops);
|
||||
if (!d)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
debugfs_remove_recursive(c->dent);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int clk_debugfs_register(struct clk *c)
|
||||
{
|
||||
int err;
|
||||
struct clk *pa = c->parent;
|
||||
|
||||
if (pa && !pa->dent) {
|
||||
err = clk_debugfs_register(pa);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!c->dent) {
|
||||
err = clk_debugfs_register_one(c);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init tegra_clk_debugfs_init(void)
|
||||
{
|
||||
struct clk *c;
|
||||
struct dentry *d;
|
||||
int err = -ENOMEM;
|
||||
|
||||
d = debugfs_create_dir("clock", NULL);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
clk_debugfs_root = d;
|
||||
|
||||
d = debugfs_create_file("clock_tree", S_IRUGO, clk_debugfs_root, NULL,
|
||||
&clock_tree_fops);
|
||||
if (!d)
|
||||
goto err_out;
|
||||
|
||||
list_for_each_entry(c, &clocks, node) {
|
||||
err = clk_debugfs_register(c);
|
||||
if (err)
|
||||
goto err_out;
|
||||
}
|
||||
return 0;
|
||||
err_out:
|
||||
debugfs_remove_recursive(clk_debugfs_root);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* arch/arm/mach-tegra/include/mach/clock.h
|
||||
*
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
* Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Colin Cross <ccross@google.com>
|
||||
|
@ -20,9 +21,9 @@
|
|||
#ifndef __MACH_TEGRA_CLOCK_H
|
||||
#define __MACH_TEGRA_CLOCK_H
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <mach/clk.h>
|
||||
|
||||
|
@ -52,7 +53,8 @@
|
|||
#define ENABLE_ON_INIT (1 << 28)
|
||||
#define PERIPH_ON_APB (1 << 29)
|
||||
|
||||
struct clk;
|
||||
struct clk_tegra;
|
||||
#define to_clk_tegra(_hw) container_of(_hw, struct clk_tegra, hw)
|
||||
|
||||
struct clk_mux_sel {
|
||||
struct clk *input;
|
||||
|
@ -68,47 +70,29 @@ struct clk_pll_freq_table {
|
|||
u8 cpcon;
|
||||
};
|
||||
|
||||
struct clk_ops {
|
||||
void (*init)(struct clk *);
|
||||
int (*enable)(struct clk *);
|
||||
void (*disable)(struct clk *);
|
||||
int (*set_parent)(struct clk *, struct clk *);
|
||||
int (*set_rate)(struct clk *, unsigned long);
|
||||
long (*round_rate)(struct clk *, unsigned long);
|
||||
void (*reset)(struct clk *, bool);
|
||||
int (*clk_cfg_ex)(struct clk *,
|
||||
enum tegra_clk_ex_param, u32);
|
||||
};
|
||||
|
||||
enum clk_state {
|
||||
UNINITIALIZED = 0,
|
||||
ON,
|
||||
OFF,
|
||||
};
|
||||
|
||||
struct clk {
|
||||
struct clk_tegra {
|
||||
/* node for master clocks list */
|
||||
struct list_head node; /* node for list of all clocks */
|
||||
struct list_head node; /* node for list of all clocks */
|
||||
struct clk_lookup lookup;
|
||||
struct clk_hw hw;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *dent;
|
||||
#endif
|
||||
bool set;
|
||||
struct clk_ops *ops;
|
||||
unsigned long rate;
|
||||
unsigned long fixed_rate;
|
||||
unsigned long max_rate;
|
||||
unsigned long min_rate;
|
||||
u32 flags;
|
||||
const char *name;
|
||||
|
||||
u32 refcnt;
|
||||
enum clk_state state;
|
||||
struct clk *parent;
|
||||
u32 div;
|
||||
u32 mul;
|
||||
|
||||
const struct clk_mux_sel *inputs;
|
||||
u32 reg;
|
||||
u32 reg_shift;
|
||||
|
||||
|
@ -144,7 +128,8 @@ struct clk {
|
|||
} shared_bus_user;
|
||||
} u;
|
||||
|
||||
spinlock_t spinlock;
|
||||
void (*reset)(struct clk_hw *, bool);
|
||||
int (*clk_cfg_ex)(struct clk_hw *, enum tegra_clk_ex_param, u32);
|
||||
};
|
||||
|
||||
struct clk_duplicate {
|
||||
|
@ -159,13 +144,10 @@ struct tegra_clk_init_table {
|
|||
bool enabled;
|
||||
};
|
||||
|
||||
void tegra_clk_add(struct clk *c);
|
||||
void tegra2_init_clocks(void);
|
||||
void tegra30_init_clocks(void);
|
||||
void clk_init(struct clk *clk);
|
||||
struct clk *tegra_get_clock_by_name(const char *name);
|
||||
int clk_reparent(struct clk *c, struct clk *parent);
|
||||
void tegra_clk_init_from_table(struct tegra_clk_init_table *table);
|
||||
unsigned long clk_get_rate_locked(struct clk *c);
|
||||
int clk_set_rate_locked(struct clk *c, unsigned long rate);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "fuse.h"
|
||||
#include "pmc.h"
|
||||
#include "apbio.h"
|
||||
#include "sleep.h"
|
||||
|
||||
/*
|
||||
* Storage for debug-macro.S's state.
|
||||
|
@ -135,6 +136,7 @@ void __init tegra20_init_early(void)
|
|||
tegra_init_cache(0x331, 0x441);
|
||||
tegra_pmc_init();
|
||||
tegra_powergate_init();
|
||||
tegra20_hotplug_init();
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
|
||||
|
@ -147,11 +149,11 @@ void __init tegra30_init_early(void)
|
|||
tegra_init_cache(0x441, 0x551);
|
||||
tegra_pmc_init();
|
||||
tegra_powergate_init();
|
||||
tegra30_hotplug_init();
|
||||
}
|
||||
#endif
|
||||
|
||||
void __init tegra_init_late(void)
|
||||
{
|
||||
tegra_clk_debugfs_init();
|
||||
tegra_powergate_debugfs_init();
|
||||
}
|
||||
|
|
|
@ -49,6 +49,8 @@ static struct cpufreq_frequency_table freq_table[] = {
|
|||
#define NUM_CPUS 2
|
||||
|
||||
static struct clk *cpu_clk;
|
||||
static struct clk *pll_x_clk;
|
||||
static struct clk *pll_p_clk;
|
||||
static struct clk *emc_clk;
|
||||
|
||||
static unsigned long target_cpu_speed[NUM_CPUS];
|
||||
|
@ -71,6 +73,42 @@ static unsigned int tegra_getspeed(unsigned int cpu)
|
|||
return rate;
|
||||
}
|
||||
|
||||
static int tegra_cpu_clk_set_rate(unsigned long rate)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Take an extra reference to the main pll so it doesn't turn
|
||||
* off when we move the cpu off of it
|
||||
*/
|
||||
clk_prepare_enable(pll_x_clk);
|
||||
|
||||
ret = clk_set_parent(cpu_clk, pll_p_clk);
|
||||
if (ret) {
|
||||
pr_err("Failed to switch cpu to clock pll_p\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rate == clk_get_rate(pll_p_clk))
|
||||
goto out;
|
||||
|
||||
ret = clk_set_rate(pll_x_clk, rate);
|
||||
if (ret) {
|
||||
pr_err("Failed to change pll_x to %lu\n", rate);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = clk_set_parent(cpu_clk, pll_x_clk);
|
||||
if (ret) {
|
||||
pr_err("Failed to switch cpu to clock pll_x\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
clk_disable_unprepare(pll_x_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tegra_update_cpu_speed(unsigned long rate)
|
||||
{
|
||||
int ret = 0;
|
||||
|
@ -101,7 +139,7 @@ static int tegra_update_cpu_speed(unsigned long rate)
|
|||
freqs.old, freqs.new);
|
||||
#endif
|
||||
|
||||
ret = clk_set_rate(cpu_clk, freqs.new * 1000);
|
||||
ret = tegra_cpu_clk_set_rate(freqs.new * 1000);
|
||||
if (ret) {
|
||||
pr_err("cpu-tegra: Failed to set cpu frequency to %d kHz\n",
|
||||
freqs.new);
|
||||
|
@ -183,6 +221,14 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)
|
|||
if (IS_ERR(cpu_clk))
|
||||
return PTR_ERR(cpu_clk);
|
||||
|
||||
pll_x_clk = clk_get_sys(NULL, "pll_x");
|
||||
if (IS_ERR(pll_x_clk))
|
||||
return PTR_ERR(pll_x_clk);
|
||||
|
||||
pll_p_clk = clk_get_sys(NULL, "pll_p");
|
||||
if (IS_ERR(pll_p_clk))
|
||||
return PTR_ERR(pll_p_clk);
|
||||
|
||||
emc_clk = clk_get_sys("cpu", "emc");
|
||||
if (IS_ERR(emc_clk)) {
|
||||
clk_put(cpu_clk);
|
||||
|
|
|
@ -7,17 +7,13 @@
|
|||
|
||||
#include "flowctrl.h"
|
||||
#include "reset.h"
|
||||
#include "sleep.h"
|
||||
|
||||
#define APB_MISC_GP_HIDREV 0x804
|
||||
#define PMC_SCRATCH41 0x140
|
||||
|
||||
#define RESET_DATA(x) ((TEGRA_RESET_##x)*4)
|
||||
|
||||
.macro mov32, reg, val
|
||||
movw \reg, #:lower16:\val
|
||||
movt \reg, #:upper16:\val
|
||||
.endm
|
||||
|
||||
.section ".text.head", "ax"
|
||||
__CPUINIT
|
||||
|
||||
|
|
|
@ -1,91 +1,23 @@
|
|||
/*
|
||||
* linux/arch/arm/mach-realview/hotplug.c
|
||||
*
|
||||
* Copyright (C) 2002 ARM Ltd.
|
||||
* All Rights Reserved
|
||||
* Copyright (c) 2010, 2012 NVIDIA Corporation. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/cp15.h>
|
||||
#include <asm/smp_plat.h>
|
||||
|
||||
static inline void cpu_enter_lowpower(void)
|
||||
{
|
||||
unsigned int v;
|
||||
#include "sleep.h"
|
||||
#include "tegra_cpu_car.h"
|
||||
|
||||
flush_cache_all();
|
||||
asm volatile(
|
||||
" mcr p15, 0, %1, c7, c5, 0\n"
|
||||
" mcr p15, 0, %1, c7, c10, 4\n"
|
||||
/*
|
||||
* Turn off coherency
|
||||
*/
|
||||
" mrc p15, 0, %0, c1, c0, 1\n"
|
||||
" bic %0, %0, #0x20\n"
|
||||
" mcr p15, 0, %0, c1, c0, 1\n"
|
||||
" mrc p15, 0, %0, c1, c0, 0\n"
|
||||
" bic %0, %0, %2\n"
|
||||
" mcr p15, 0, %0, c1, c0, 0\n"
|
||||
: "=&r" (v)
|
||||
: "r" (0), "Ir" (CR_C)
|
||||
: "cc");
|
||||
}
|
||||
|
||||
static inline void cpu_leave_lowpower(void)
|
||||
{
|
||||
unsigned int v;
|
||||
|
||||
asm volatile(
|
||||
"mrc p15, 0, %0, c1, c0, 0\n"
|
||||
" orr %0, %0, %1\n"
|
||||
" mcr p15, 0, %0, c1, c0, 0\n"
|
||||
" mrc p15, 0, %0, c1, c0, 1\n"
|
||||
" orr %0, %0, #0x20\n"
|
||||
" mcr p15, 0, %0, c1, c0, 1\n"
|
||||
: "=&r" (v)
|
||||
: "Ir" (CR_C)
|
||||
: "cc");
|
||||
}
|
||||
|
||||
static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
|
||||
{
|
||||
/*
|
||||
* there is no power-control hardware on this platform, so all
|
||||
* we can do is put the core into WFI; this is safe as the calling
|
||||
* code will have already disabled interrupts
|
||||
*/
|
||||
for (;;) {
|
||||
/*
|
||||
* here's the WFI
|
||||
*/
|
||||
asm(".word 0xe320f003\n"
|
||||
:
|
||||
:
|
||||
: "memory", "cc");
|
||||
|
||||
/*if (pen_release == cpu) {*/
|
||||
/*
|
||||
* OK, proper wakeup, we're done
|
||||
*/
|
||||
break;
|
||||
/*}*/
|
||||
|
||||
/*
|
||||
* Getting here, means that we have come out of WFI without
|
||||
* having been woken up - this shouldn't happen
|
||||
*
|
||||
* Just note it happening - when we're woken, we can report
|
||||
* its occurrence.
|
||||
*/
|
||||
(*spurious)++;
|
||||
}
|
||||
}
|
||||
static void (*tegra_hotplug_shutdown)(void);
|
||||
|
||||
int platform_cpu_kill(unsigned int cpu)
|
||||
{
|
||||
|
@ -99,22 +31,20 @@ int platform_cpu_kill(unsigned int cpu)
|
|||
*/
|
||||
void platform_cpu_die(unsigned int cpu)
|
||||
{
|
||||
int spurious = 0;
|
||||
cpu = cpu_logical_map(cpu);
|
||||
|
||||
/*
|
||||
* we're ready for shutdown now, so do it
|
||||
*/
|
||||
cpu_enter_lowpower();
|
||||
platform_do_lowpower(cpu, &spurious);
|
||||
/* Flush the L1 data cache. */
|
||||
flush_cache_all();
|
||||
|
||||
/*
|
||||
* bring this CPU back into the world of cache
|
||||
* coherency, and then restore interrupts
|
||||
*/
|
||||
cpu_leave_lowpower();
|
||||
/* Shut down the current CPU. */
|
||||
tegra_hotplug_shutdown();
|
||||
|
||||
if (spurious)
|
||||
pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
|
||||
/* Clock gate the CPU */
|
||||
tegra_wait_cpu_in_reset(cpu);
|
||||
tegra_disable_cpu_clock(cpu);
|
||||
|
||||
/* Should never return here. */
|
||||
BUG();
|
||||
}
|
||||
|
||||
int platform_cpu_disable(unsigned int cpu)
|
||||
|
@ -125,3 +55,19 @@ int platform_cpu_disable(unsigned int cpu)
|
|||
*/
|
||||
return cpu == 0 ? -EPERM : 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
extern void tegra20_hotplug_shutdown(void);
|
||||
void __init tegra20_hotplug_init(void)
|
||||
{
|
||||
tegra_hotplug_shutdown = tegra20_hotplug_shutdown;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
|
||||
extern void tegra30_hotplug_shutdown(void);
|
||||
void __init tegra30_hotplug_init(void)
|
||||
{
|
||||
tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -34,7 +34,10 @@ enum tegra_clk_ex_param {
|
|||
void tegra_periph_reset_deassert(struct clk *c);
|
||||
void tegra_periph_reset_assert(struct clk *c);
|
||||
|
||||
#ifndef CONFIG_COMMON_CLK
|
||||
unsigned long clk_get_rate_all_locked(struct clk *c);
|
||||
#endif
|
||||
|
||||
void tegra2_sdmmc_tap_delay(struct clk *c, int delay);
|
||||
int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting);
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "fuse.h"
|
||||
#include "flowctrl.h"
|
||||
#include "reset.h"
|
||||
#include "tegra_cpu_car.h"
|
||||
|
||||
extern void tegra_secondary_startup(void);
|
||||
|
||||
|
@ -38,17 +39,6 @@ static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE);
|
|||
|
||||
#define EVP_CPU_RESET_VECTOR \
|
||||
(IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100)
|
||||
#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX \
|
||||
(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x4c)
|
||||
#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET \
|
||||
(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x340)
|
||||
#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR \
|
||||
(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x344)
|
||||
#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR \
|
||||
(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x34c)
|
||||
|
||||
#define CPU_CLOCK(cpu) (0x1<<(8+cpu))
|
||||
#define CPU_RESET(cpu) (0x1111ul<<(cpu))
|
||||
|
||||
void __cpuinit platform_secondary_init(unsigned int cpu)
|
||||
{
|
||||
|
@ -63,13 +53,8 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
|
|||
|
||||
static int tegra20_power_up_cpu(unsigned int cpu)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
/* Enable the CPU clock. */
|
||||
reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
|
||||
writel(reg & ~CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
|
||||
barrier();
|
||||
reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
|
||||
tegra_enable_cpu_clock(cpu);
|
||||
|
||||
/* Clear flow controller CSR. */
|
||||
flowctrl_write_cpu_csr(cpu, 0);
|
||||
|
@ -79,7 +64,6 @@ static int tegra20_power_up_cpu(unsigned int cpu)
|
|||
|
||||
static int tegra30_power_up_cpu(unsigned int cpu)
|
||||
{
|
||||
u32 reg;
|
||||
int ret, pwrgateid;
|
||||
unsigned long timeout;
|
||||
|
||||
|
@ -103,8 +87,7 @@ static int tegra30_power_up_cpu(unsigned int cpu)
|
|||
}
|
||||
|
||||
/* CPU partition is powered. Enable the CPU clock. */
|
||||
writel(CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
|
||||
reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
|
||||
tegra_enable_cpu_clock(cpu);
|
||||
udelay(10);
|
||||
|
||||
/* Remove I/O clamps. */
|
||||
|
@ -128,8 +111,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
|
|||
* via the flow controller). This will have no effect on first boot
|
||||
* of the CPU since it should already be in reset.
|
||||
*/
|
||||
writel(CPU_RESET(cpu), CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
|
||||
dmb();
|
||||
tegra_put_cpu_in_reset(cpu);
|
||||
|
||||
/*
|
||||
* Unhalt the CPU. If the flow controller was used to power-gate the
|
||||
|
@ -155,8 +137,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
|
|||
goto done;
|
||||
|
||||
/* Take the CPU out of reset. */
|
||||
writel(CPU_RESET(cpu), CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
|
||||
wmb();
|
||||
tegra_cpu_out_of_reset(cpu);
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
|
||||
* Copyright (c) 2011, Google, Inc.
|
||||
*
|
||||
* Author: Colin Cross <ccross@android.com>
|
||||
* Gary King <gking@nvidia.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
#include <asm/assembler.h>
|
||||
|
||||
#include <mach/iomap.h>
|
||||
|
||||
#include "sleep.h"
|
||||
#include "flowctrl.h"
|
||||
|
||||
#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
|
||||
/*
|
||||
* tegra20_hotplug_shutdown(void)
|
||||
*
|
||||
* puts the current cpu in reset
|
||||
* should never return
|
||||
*/
|
||||
ENTRY(tegra20_hotplug_shutdown)
|
||||
/* Turn off SMP coherency */
|
||||
exit_smp r4, r5
|
||||
|
||||
/* Put this CPU down */
|
||||
cpu_id r0
|
||||
bl tegra20_cpu_shutdown
|
||||
mov pc, lr @ should never get here
|
||||
ENDPROC(tegra20_hotplug_shutdown)
|
||||
|
||||
/*
|
||||
* tegra20_cpu_shutdown(int cpu)
|
||||
*
|
||||
* r0 is cpu to reset
|
||||
*
|
||||
* puts the specified CPU in wait-for-event mode on the flow controller
|
||||
* and puts the CPU in reset
|
||||
* can be called on the current cpu or another cpu
|
||||
* if called on the current cpu, does not return
|
||||
* MUST NOT BE CALLED FOR CPU 0.
|
||||
*
|
||||
* corrupts r0-r3, r12
|
||||
*/
|
||||
ENTRY(tegra20_cpu_shutdown)
|
||||
cmp r0, #0
|
||||
moveq pc, lr @ must not be called for CPU 0
|
||||
|
||||
cpu_to_halt_reg r1, r0
|
||||
ldr r3, =TEGRA_FLOW_CTRL_VIRT
|
||||
mov r2, #FLOW_CTRL_WAITEVENT | FLOW_CTRL_JTAG_RESUME
|
||||
str r2, [r3, r1] @ put flow controller in wait event mode
|
||||
ldr r2, [r3, r1]
|
||||
isb
|
||||
dsb
|
||||
movw r1, 0x1011
|
||||
mov r1, r1, lsl r0
|
||||
ldr r3, =TEGRA_CLK_RESET_VIRT
|
||||
str r1, [r3, #0x340] @ put slave CPU in reset
|
||||
isb
|
||||
dsb
|
||||
cpu_id r3
|
||||
cmp r3, r0
|
||||
beq .
|
||||
mov pc, lr
|
||||
ENDPROC(tegra20_cpu_shutdown)
|
||||
#endif
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright (c) 2012, NVIDIA Corporation. All rights reserved.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
#include <asm/assembler.h>
|
||||
|
||||
#include <mach/iomap.h>
|
||||
|
||||
#include "sleep.h"
|
||||
#include "flowctrl.h"
|
||||
|
||||
#define TEGRA30_POWER_HOTPLUG_SHUTDOWN (1 << 27) /* Hotplug shutdown */
|
||||
|
||||
#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
|
||||
/*
|
||||
* tegra30_hotplug_shutdown(void)
|
||||
*
|
||||
* Powergates the current CPU.
|
||||
* Should never return.
|
||||
*/
|
||||
ENTRY(tegra30_hotplug_shutdown)
|
||||
/* Turn off SMP coherency */
|
||||
exit_smp r4, r5
|
||||
|
||||
/* Powergate this CPU */
|
||||
mov r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN
|
||||
bl tegra30_cpu_shutdown
|
||||
mov pc, lr @ should never get here
|
||||
ENDPROC(tegra30_hotplug_shutdown)
|
||||
|
||||
/*
|
||||
* tegra30_cpu_shutdown(unsigned long flags)
|
||||
*
|
||||
* Puts the current CPU in wait-for-event mode on the flow controller
|
||||
* and powergates it -- flags (in R0) indicate the request type.
|
||||
* Must never be called for CPU 0.
|
||||
*
|
||||
* corrupts r0-r4, r12
|
||||
*/
|
||||
ENTRY(tegra30_cpu_shutdown)
|
||||
cpu_id r3
|
||||
cmp r3, #0
|
||||
moveq pc, lr @ Must never be called for CPU 0
|
||||
|
||||
ldr r12, =TEGRA_FLOW_CTRL_VIRT
|
||||
cpu_to_csr_reg r1, r3
|
||||
add r1, r1, r12 @ virtual CSR address for this CPU
|
||||
cpu_to_halt_reg r2, r3
|
||||
add r2, r2, r12 @ virtual HALT_EVENTS address for this CPU
|
||||
|
||||
/*
|
||||
* Clear this CPU's "event" and "interrupt" flags and power gate
|
||||
* it when halting but not before it is in the "WFE" state.
|
||||
*/
|
||||
movw r12, \
|
||||
FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | \
|
||||
FLOW_CTRL_CSR_ENABLE
|
||||
mov r4, #(1 << 4)
|
||||
orr r12, r12, r4, lsl r3
|
||||
str r12, [r1]
|
||||
|
||||
/* Halt this CPU. */
|
||||
mov r3, #0x400
|
||||
delay_1:
|
||||
subs r3, r3, #1 @ delay as a part of wfe war.
|
||||
bge delay_1;
|
||||
cpsid a @ disable imprecise aborts.
|
||||
ldr r3, [r1] @ read CSR
|
||||
str r3, [r1] @ clear CSR
|
||||
tst r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN
|
||||
movne r3, #FLOW_CTRL_WAITEVENT @ For hotplug
|
||||
str r3, [r2]
|
||||
ldr r0, [r2]
|
||||
b wfe_war
|
||||
|
||||
__cpu_reset_again:
|
||||
dsb
|
||||
.align 5
|
||||
wfe @ CPU should be power gated here
|
||||
wfe_war:
|
||||
b __cpu_reset_again
|
||||
|
||||
/*
|
||||
* 38 nop's, which fills reset of wfe cache line and
|
||||
* 4 more cachelines with nop
|
||||
*/
|
||||
.rept 38
|
||||
nop
|
||||
.endr
|
||||
b . @ should never get here
|
||||
|
||||
ENDPROC(tegra30_cpu_shutdown)
|
||||
#endif
|
|
@ -29,36 +29,5 @@
|
|||
#include <mach/iomap.h>
|
||||
|
||||
#include "flowctrl.h"
|
||||
#include "sleep.h"
|
||||
|
||||
#define TEGRA_FLOW_CTRL_VIRT (TEGRA_FLOW_CTRL_BASE - IO_PPSB_PHYS \
|
||||
+ IO_PPSB_VIRT)
|
||||
|
||||
/* returns the offset of the flow controller halt register for a cpu */
|
||||
.macro cpu_to_halt_reg rd, rcpu
|
||||
cmp \rcpu, #0
|
||||
subne \rd, \rcpu, #1
|
||||
movne \rd, \rd, lsl #3
|
||||
addne \rd, \rd, #0x14
|
||||
moveq \rd, #0
|
||||
.endm
|
||||
|
||||
/* returns the offset of the flow controller csr register for a cpu */
|
||||
.macro cpu_to_csr_reg rd, rcpu
|
||||
cmp \rcpu, #0
|
||||
subne \rd, \rcpu, #1
|
||||
movne \rd, \rd, lsl #3
|
||||
addne \rd, \rd, #0x18
|
||||
moveq \rd, #8
|
||||
.endm
|
||||
|
||||
/* returns the ID of the current processor */
|
||||
.macro cpu_id, rd
|
||||
mrc p15, 0, \rd, c0, c0, 5
|
||||
and \rd, \rd, #0xF
|
||||
.endm
|
||||
|
||||
/* loads a 32-bit value into a register without a data access */
|
||||
.macro mov32, reg, val
|
||||
movw \reg, #:lower16:\val
|
||||
movt \reg, #:upper16:\val
|
||||
.endm
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __MACH_TEGRA_SLEEP_H
|
||||
#define __MACH_TEGRA_SLEEP_H
|
||||
|
||||
#include <mach/iomap.h>
|
||||
|
||||
#define TEGRA_ARM_PERIF_VIRT (TEGRA_ARM_PERIF_BASE - IO_CPU_PHYS \
|
||||
+ IO_CPU_VIRT)
|
||||
#define TEGRA_FLOW_CTRL_VIRT (TEGRA_FLOW_CTRL_BASE - IO_PPSB_PHYS \
|
||||
+ IO_PPSB_VIRT)
|
||||
#define TEGRA_CLK_RESET_VIRT (TEGRA_CLK_RESET_BASE - IO_PPSB_PHYS \
|
||||
+ IO_PPSB_VIRT)
|
||||
|
||||
#ifdef __ASSEMBLY__
|
||||
/* returns the offset of the flow controller halt register for a cpu */
|
||||
.macro cpu_to_halt_reg rd, rcpu
|
||||
cmp \rcpu, #0
|
||||
subne \rd, \rcpu, #1
|
||||
movne \rd, \rd, lsl #3
|
||||
addne \rd, \rd, #0x14
|
||||
moveq \rd, #0
|
||||
.endm
|
||||
|
||||
/* returns the offset of the flow controller csr register for a cpu */
|
||||
.macro cpu_to_csr_reg rd, rcpu
|
||||
cmp \rcpu, #0
|
||||
subne \rd, \rcpu, #1
|
||||
movne \rd, \rd, lsl #3
|
||||
addne \rd, \rd, #0x18
|
||||
moveq \rd, #8
|
||||
.endm
|
||||
|
||||
/* returns the ID of the current processor */
|
||||
.macro cpu_id, rd
|
||||
mrc p15, 0, \rd, c0, c0, 5
|
||||
and \rd, \rd, #0xF
|
||||
.endm
|
||||
|
||||
/* loads a 32-bit value into a register without a data access */
|
||||
.macro mov32, reg, val
|
||||
movw \reg, #:lower16:\val
|
||||
movt \reg, #:upper16:\val
|
||||
.endm
|
||||
|
||||
/* Macro to exit SMP coherency. */
|
||||
.macro exit_smp, tmp1, tmp2
|
||||
mrc p15, 0, \tmp1, c1, c0, 1 @ ACTLR
|
||||
bic \tmp1, \tmp1, #(1<<6) | (1<<0) @ clear ACTLR.SMP | ACTLR.FW
|
||||
mcr p15, 0, \tmp1, c1, c0, 1 @ ACTLR
|
||||
isb
|
||||
cpu_id \tmp1
|
||||
mov \tmp1, \tmp1, lsl #2
|
||||
mov \tmp2, #0xf
|
||||
mov \tmp2, \tmp2, lsl \tmp1
|
||||
mov32 \tmp1, TEGRA_ARM_PERIF_VIRT + 0xC
|
||||
str \tmp2, [\tmp1] @ invalidate SCU tags for CPU
|
||||
dsb
|
||||
.endm
|
||||
#else
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
void tegra20_hotplug_init(void);
|
||||
void tegra30_hotplug_init(void);
|
||||
#else
|
||||
static inline void tegra20_hotplug_init(void) {}
|
||||
static inline void tegra30_hotplug_init(void) {}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __MACH_TEGRA20_CLOCK_H
|
||||
#define __MACH_TEGRA20_CLOCK_H
|
||||
|
||||
extern struct clk_ops tegra_clk_32k_ops;
|
||||
extern struct clk_ops tegra_pll_ops;
|
||||
extern struct clk_ops tegra_clk_m_ops;
|
||||
extern struct clk_ops tegra_pll_div_ops;
|
||||
extern struct clk_ops tegra_pllx_ops;
|
||||
extern struct clk_ops tegra_plle_ops;
|
||||
extern struct clk_ops tegra_clk_double_ops;
|
||||
extern struct clk_ops tegra_cdev_clk_ops;
|
||||
extern struct clk_ops tegra_audio_sync_clk_ops;
|
||||
extern struct clk_ops tegra_super_ops;
|
||||
extern struct clk_ops tegra_cpu_ops;
|
||||
extern struct clk_ops tegra_twd_ops;
|
||||
extern struct clk_ops tegra_cop_ops;
|
||||
extern struct clk_ops tegra_bus_ops;
|
||||
extern struct clk_ops tegra_blink_clk_ops;
|
||||
extern struct clk_ops tegra_emc_clk_ops;
|
||||
extern struct clk_ops tegra_periph_clk_ops;
|
||||
extern struct clk_ops tegra_clk_shared_bus_ops;
|
||||
|
||||
void tegra2_periph_clk_reset(struct clk_hw *hw, bool assert);
|
||||
void tegra2_cop_clk_reset(struct clk_hw *hw, bool assert);
|
||||
|
||||
#endif
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __MACH_TEGRA30_CLOCK_H
|
||||
#define __MACH_TEGRA30_CLOCK_H
|
||||
|
||||
extern struct clk_ops tegra30_clk_32k_ops;
|
||||
extern struct clk_ops tegra30_clk_m_ops;
|
||||
extern struct clk_ops tegra_clk_m_div_ops;
|
||||
extern struct clk_ops tegra_pll_ref_ops;
|
||||
extern struct clk_ops tegra30_pll_ops;
|
||||
extern struct clk_ops tegra30_pll_div_ops;
|
||||
extern struct clk_ops tegra_plld_ops;
|
||||
extern struct clk_ops tegra30_plle_ops;
|
||||
extern struct clk_ops tegra_cml_clk_ops;
|
||||
extern struct clk_ops tegra_pciex_clk_ops;
|
||||
extern struct clk_ops tegra_sync_source_ops;
|
||||
extern struct clk_ops tegra30_audio_sync_clk_ops;
|
||||
extern struct clk_ops tegra30_clk_double_ops;
|
||||
extern struct clk_ops tegra_clk_out_ops;
|
||||
extern struct clk_ops tegra30_super_ops;
|
||||
extern struct clk_ops tegra30_blink_clk_ops;
|
||||
extern struct clk_ops tegra30_twd_ops;
|
||||
extern struct clk_ops tegra30_periph_clk_ops;
|
||||
extern struct clk_ops tegra30_dsib_clk_ops;
|
||||
extern struct clk_ops tegra_nand_clk_ops;
|
||||
extern struct clk_ops tegra_vi_clk_ops;
|
||||
extern struct clk_ops tegra_dtv_clk_ops;
|
||||
extern struct clk_ops tegra_clk_shared_bus_ops;
|
||||
|
||||
int tegra30_plld_clk_cfg_ex(struct clk_hw *hw,
|
||||
enum tegra_clk_ex_param p, u32 setting);
|
||||
void tegra30_periph_clk_reset(struct clk_hw *hw, bool assert);
|
||||
int tegra30_vi_clk_cfg_ex(struct clk_hw *hw,
|
||||
enum tegra_clk_ex_param p, u32 setting);
|
||||
int tegra30_nand_clk_cfg_ex(struct clk_hw *hw,
|
||||
enum tegra_clk_ex_param p, u32 setting);
|
||||
int tegra30_dtv_clk_cfg_ex(struct clk_hw *hw,
|
||||
enum tegra_clk_ex_param p, u32 setting);
|
||||
#endif
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __MACH_TEGRA_CPU_CAR_H
|
||||
#define __MACH_TEGRA_CPU_CAR_H
|
||||
|
||||
/*
|
||||
* Tegra CPU clock and reset control ops
|
||||
*
|
||||
* wait_for_reset:
|
||||
* keep waiting until the CPU in reset state
|
||||
* put_in_reset:
|
||||
* put the CPU in reset state
|
||||
* out_of_reset:
|
||||
* release the CPU from reset state
|
||||
* enable_clock:
|
||||
* CPU clock un-gate
|
||||
* disable_clock:
|
||||
* CPU clock gate
|
||||
*/
|
||||
struct tegra_cpu_car_ops {
|
||||
void (*wait_for_reset)(u32 cpu);
|
||||
void (*put_in_reset)(u32 cpu);
|
||||
void (*out_of_reset)(u32 cpu);
|
||||
void (*enable_clock)(u32 cpu);
|
||||
void (*disable_clock)(u32 cpu);
|
||||
};
|
||||
|
||||
extern struct tegra_cpu_car_ops *tegra_cpu_car_ops;
|
||||
|
||||
static inline void tegra_wait_cpu_in_reset(u32 cpu)
|
||||
{
|
||||
if (WARN_ON(!tegra_cpu_car_ops->wait_for_reset))
|
||||
return;
|
||||
|
||||
tegra_cpu_car_ops->wait_for_reset(cpu);
|
||||
}
|
||||
|
||||
static inline void tegra_put_cpu_in_reset(u32 cpu)
|
||||
{
|
||||
if (WARN_ON(!tegra_cpu_car_ops->put_in_reset))
|
||||
return;
|
||||
|
||||
tegra_cpu_car_ops->put_in_reset(cpu);
|
||||
}
|
||||
|
||||
static inline void tegra_cpu_out_of_reset(u32 cpu)
|
||||
{
|
||||
if (WARN_ON(!tegra_cpu_car_ops->out_of_reset))
|
||||
return;
|
||||
|
||||
tegra_cpu_car_ops->out_of_reset(cpu);
|
||||
}
|
||||
|
||||
static inline void tegra_enable_cpu_clock(u32 cpu)
|
||||
{
|
||||
if (WARN_ON(!tegra_cpu_car_ops->enable_clock))
|
||||
return;
|
||||
|
||||
tegra_cpu_car_ops->enable_clock(cpu);
|
||||
}
|
||||
|
||||
static inline void tegra_disable_cpu_clock(u32 cpu)
|
||||
{
|
||||
if (WARN_ON(!tegra_cpu_car_ops->disable_clock))
|
||||
return;
|
||||
|
||||
tegra_cpu_car_ops->disable_clock(cpu);
|
||||
}
|
||||
|
||||
void tegra20_cpu_car_ops_init(void);
|
||||
void tegra30_cpu_car_ops_init(void);
|
||||
|
||||
#endif /* __MACH_TEGRA_CPU_CAR_H */
|
|
@ -38,7 +38,7 @@ static int __init ux500_l2x0_init(void)
|
|||
{
|
||||
u32 aux_val = 0x3e000000;
|
||||
|
||||
if (cpu_is_u8500_family())
|
||||
if (cpu_is_u8500_family() || cpu_is_ux540_family())
|
||||
l2x0_base = __io_address(U8500_L2CC_BASE);
|
||||
else
|
||||
ux500_unknown_soc();
|
||||
|
|
|
@ -79,7 +79,7 @@ void __init u8500_map_io(void)
|
|||
|
||||
iotable_init(u8500_common_io_desc, ARRAY_SIZE(u8500_common_io_desc));
|
||||
|
||||
if (cpu_is_u9540())
|
||||
if (cpu_is_ux540_family())
|
||||
iotable_init(u9540_io_desc, ARRAY_SIZE(u9540_io_desc));
|
||||
else
|
||||
iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc));
|
||||
|
|
|
@ -49,7 +49,7 @@ void __init ux500_init_irq(void)
|
|||
void __iomem *dist_base;
|
||||
void __iomem *cpu_base;
|
||||
|
||||
if (cpu_is_u8500_family()) {
|
||||
if (cpu_is_u8500_family() || cpu_is_ux540_family()) {
|
||||
dist_base = __io_address(U8500_GIC_DIST_BASE);
|
||||
cpu_base = __io_address(U8500_GIC_CPU_BASE);
|
||||
} else
|
||||
|
|
|
@ -41,43 +41,29 @@ static inline bool __attribute_const__ cpu_is_u8500(void)
|
|||
return dbx500_partnumber() == 0x8500;
|
||||
}
|
||||
|
||||
static inline bool __attribute_const__ cpu_is_u8520(void)
|
||||
{
|
||||
return dbx500_partnumber() == 0x8520;
|
||||
}
|
||||
|
||||
static inline bool cpu_is_u8500_family(void)
|
||||
{
|
||||
return cpu_is_u8500() || cpu_is_u8520();
|
||||
}
|
||||
|
||||
static inline bool __attribute_const__ cpu_is_u9540(void)
|
||||
{
|
||||
return dbx500_partnumber() == 0x9540;
|
||||
}
|
||||
|
||||
static inline bool cpu_is_u8500_family(void)
|
||||
static inline bool __attribute_const__ cpu_is_u8540(void)
|
||||
{
|
||||
return cpu_is_u8500() || cpu_is_u9540();
|
||||
return dbx500_partnumber() == 0x8540;
|
||||
}
|
||||
|
||||
static inline bool __attribute_const__ cpu_is_u5500(void)
|
||||
static inline bool cpu_is_ux540_family(void)
|
||||
{
|
||||
return dbx500_partnumber() == 0x5500;
|
||||
}
|
||||
|
||||
/*
|
||||
* 5500 revisions
|
||||
*/
|
||||
|
||||
static inline bool __attribute_const__ cpu_is_u5500v1(void)
|
||||
{
|
||||
return cpu_is_u5500() && (dbx500_revision() & 0xf0) == 0xA0;
|
||||
}
|
||||
|
||||
static inline bool __attribute_const__ cpu_is_u5500v2(void)
|
||||
{
|
||||
return (dbx500_id.revision & 0xf0) == 0xB0;
|
||||
}
|
||||
|
||||
static inline bool __attribute_const__ cpu_is_u5500v20(void)
|
||||
{
|
||||
return cpu_is_u5500() && ((dbx500_revision() & 0xf0) == 0xB0);
|
||||
}
|
||||
|
||||
static inline bool __attribute_const__ cpu_is_u5500v21(void)
|
||||
{
|
||||
return cpu_is_u5500() && (dbx500_revision() == 0xB1);
|
||||
return cpu_is_u9540() || cpu_is_u8540();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -119,14 +105,14 @@ static inline bool cpu_is_u8500v21(void)
|
|||
return cpu_is_u8500() && (dbx500_revision() == 0xB1);
|
||||
}
|
||||
|
||||
static inline bool cpu_is_u8500v22(void)
|
||||
{
|
||||
return cpu_is_u8500() && (dbx500_revision() == 0xB2);
|
||||
}
|
||||
|
||||
static inline bool cpu_is_u8500v20_or_later(void)
|
||||
{
|
||||
/*
|
||||
* U9540 has so much in common with U8500 that is is considered a
|
||||
* U8500 variant.
|
||||
*/
|
||||
return cpu_is_u9540() ||
|
||||
(cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11());
|
||||
return (cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11());
|
||||
}
|
||||
|
||||
static inline bool ux500_is_svp(void)
|
||||
|
|
|
@ -48,7 +48,7 @@ static void write_pen_release(int val)
|
|||
|
||||
static void __iomem *scu_base_addr(void)
|
||||
{
|
||||
if (cpu_is_u8500_family())
|
||||
if (cpu_is_u8500_family() || cpu_is_ux540_family())
|
||||
return __io_address(U8500_SCU_BASE);
|
||||
else
|
||||
ux500_unknown_soc();
|
||||
|
@ -118,7 +118,7 @@ static void __init wakeup_secondary(void)
|
|||
{
|
||||
void __iomem *backupram;
|
||||
|
||||
if (cpu_is_u8500_family())
|
||||
if (cpu_is_u8500_family() || cpu_is_ux540_family())
|
||||
backupram = __io_address(U8500_BACKUPRAM0_BASE);
|
||||
else
|
||||
ux500_unknown_soc();
|
||||
|
|
|
@ -54,7 +54,7 @@ static void __init ux500_timer_init(void)
|
|||
void __iomem *tmp_base;
|
||||
struct device_node *np;
|
||||
|
||||
if (cpu_is_u8500_family()) {
|
||||
if (cpu_is_u8500_family() || cpu_is_ux540_family()) {
|
||||
mtu_timer_base = __io_address(U8500_MTU0_BASE);
|
||||
prcmu_timer_base = __io_address(U8500_PRCMU_TIMER_4_BASE);
|
||||
} else {
|
||||
|
|
|
@ -512,12 +512,16 @@ enum iomux_pins {
|
|||
#define MX31_PIN_CSPI3_SPI_RDY__CTS3 IOMUX_MODE(MX31_PIN_CSPI3_SPI_RDY, IOMUX_CONFIG_ALT1)
|
||||
#define MX31_PIN_CTS1__CTS1 IOMUX_MODE(MX31_PIN_CTS1, IOMUX_CONFIG_FUNC)
|
||||
#define MX31_PIN_RTS1__RTS1 IOMUX_MODE(MX31_PIN_RTS1, IOMUX_CONFIG_FUNC)
|
||||
#define MX31_PIN_RTS1__SFS IOMUX_MODE(MX31_PIN_RTS1, IOMUX_CONFIG_ALT2)
|
||||
#define MX31_PIN_TXD1__TXD1 IOMUX_MODE(MX31_PIN_TXD1, IOMUX_CONFIG_FUNC)
|
||||
#define MX31_PIN_TXD1__SCK IOMUX_MODE(MX31_PIN_TXD1, IOMUX_CONFIG_ALT2)
|
||||
#define MX31_PIN_RXD1__RXD1 IOMUX_MODE(MX31_PIN_RXD1, IOMUX_CONFIG_FUNC)
|
||||
#define MX31_PIN_RXD1__STXDA IOMUX_MODE(MX31_PIN_RXD1, IOMUX_CONFIG_ALT2)
|
||||
#define MX31_PIN_DCD_DCE1__DCD_DCE1 IOMUX_MODE(MX31_PIN_DCD_DCE1, IOMUX_CONFIG_FUNC)
|
||||
#define MX31_PIN_RI_DCE1__RI_DCE1 IOMUX_MODE(MX31_PIN_RI_DCE1, IOMUX_CONFIG_FUNC)
|
||||
#define MX31_PIN_DSR_DCE1__DSR_DCE1 IOMUX_MODE(MX31_PIN_DSR_DCE1, IOMUX_CONFIG_FUNC)
|
||||
#define MX31_PIN_DTR_DCE1__DTR_DCE1 IOMUX_MODE(MX31_PIN_DTR_DCE1, IOMUX_CONFIG_FUNC)
|
||||
#define MX31_PIN_DTR_DCE1__SRXDA IOMUX_MODE(MX31_PIN_DTR_DCE1, IOMUX_CONFIG_ALT2)
|
||||
#define MX31_PIN_CTS2__CTS2 IOMUX_MODE(MX31_PIN_CTS2, IOMUX_CONFIG_FUNC)
|
||||
#define MX31_PIN_RTS2__RTS2 IOMUX_MODE(MX31_PIN_RTS2, IOMUX_CONFIG_FUNC)
|
||||
#define MX31_PIN_TXD2__TXD2 IOMUX_MODE(MX31_PIN_TXD2, IOMUX_CONFIG_FUNC)
|
||||
|
@ -721,6 +725,7 @@ enum iomux_pins {
|
|||
#define MX31_PIN_KEY_ROW2_KEY_ROW2 IOMUX_MODE(MX31_PIN_KEY_ROW2, IOMUX_CONFIG_FUNC)
|
||||
#define MX31_PIN_KEY_ROW3_KEY_ROW3 IOMUX_MODE(MX31_PIN_KEY_ROW3, IOMUX_CONFIG_FUNC)
|
||||
#define MX31_PIN_KEY_ROW4_KEY_ROW4 IOMUX_MODE(MX31_PIN_KEY_ROW4, IOMUX_CONFIG_FUNC)
|
||||
#define MX31_PIN_KEY_ROW4_GPIO IOMUX_MODE(MX31_PIN_KEY_ROW4, IOMUX_CONFIG_GPIO)
|
||||
#define MX31_PIN_KEY_ROW5_KEY_ROW5 IOMUX_MODE(MX31_PIN_KEY_ROW5, IOMUX_CONFIG_FUNC)
|
||||
#define MX31_PIN_KEY_ROW6_KEY_ROW6 IOMUX_MODE(MX31_PIN_KEY_ROW6, IOMUX_CONFIG_FUNC)
|
||||
#define MX31_PIN_KEY_ROW7_KEY_ROW7 IOMUX_MODE(MX31_PIN_KEY_ROW7, IOMUX_CONFIG_FUNC)
|
||||
|
|
|
@ -34,91 +34,98 @@
|
|||
.global imx_ssi_fiq_rx_buffer
|
||||
.global imx_ssi_fiq_tx_buffer
|
||||
|
||||
/*
|
||||
* imx_ssi_fiq_start is _intentionally_ not marked as a function symbol
|
||||
* using ENDPROC(). imx_ssi_fiq_start and imx_ssi_fiq_end are used to
|
||||
* mark the function body so that it can be copied to the FIQ vector in
|
||||
* the vectors page. imx_ssi_fiq_start should only be called as the result
|
||||
* of an FIQ: calling it directly will not work.
|
||||
*/
|
||||
imx_ssi_fiq_start:
|
||||
ldr r12, imx_ssi_fiq_base
|
||||
ldr r12, .L_imx_ssi_fiq_base
|
||||
|
||||
/* TX */
|
||||
ldr r11, imx_ssi_fiq_tx_buffer
|
||||
ldr r13, .L_imx_ssi_fiq_tx_buffer
|
||||
|
||||
/* shall we send? */
|
||||
ldr r13, [r12, #SSI_SIER]
|
||||
tst r13, #SSI_SIER_TFE0_EN
|
||||
ldr r11, [r12, #SSI_SIER]
|
||||
tst r11, #SSI_SIER_TFE0_EN
|
||||
beq 1f
|
||||
|
||||
/* TX FIFO empty? */
|
||||
ldr r13, [r12, #SSI_SISR]
|
||||
tst r13, #SSI_SISR_TFE0
|
||||
ldr r11, [r12, #SSI_SISR]
|
||||
tst r11, #SSI_SISR_TFE0
|
||||
beq 1f
|
||||
|
||||
mov r10, #0x10000
|
||||
sub r10, #1
|
||||
and r10, r10, r8 /* r10: current buffer offset */
|
||||
|
||||
add r11, r11, r10
|
||||
add r13, r13, r10
|
||||
|
||||
ldrh r13, [r11]
|
||||
strh r13, [r12, #SSI_STX0]
|
||||
ldrh r11, [r13]
|
||||
strh r11, [r12, #SSI_STX0]
|
||||
|
||||
ldrh r13, [r11, #2]
|
||||
strh r13, [r12, #SSI_STX0]
|
||||
ldrh r11, [r13, #2]
|
||||
strh r11, [r12, #SSI_STX0]
|
||||
|
||||
ldrh r13, [r11, #4]
|
||||
strh r13, [r12, #SSI_STX0]
|
||||
ldrh r11, [r13, #4]
|
||||
strh r11, [r12, #SSI_STX0]
|
||||
|
||||
ldrh r13, [r11, #6]
|
||||
strh r13, [r12, #SSI_STX0]
|
||||
ldrh r11, [r13, #6]
|
||||
strh r11, [r12, #SSI_STX0]
|
||||
|
||||
add r10, #8
|
||||
lsr r13, r8, #16 /* r13: buffer size */
|
||||
cmp r10, r13
|
||||
lslgt r8, r13, #16
|
||||
lsr r11, r8, #16 /* r11: buffer size */
|
||||
cmp r10, r11
|
||||
lslgt r8, r11, #16
|
||||
addle r8, #8
|
||||
1:
|
||||
/* RX */
|
||||
|
||||
/* shall we receive? */
|
||||
ldr r13, [r12, #SSI_SIER]
|
||||
tst r13, #SSI_SIER_RFF0_EN
|
||||
ldr r11, [r12, #SSI_SIER]
|
||||
tst r11, #SSI_SIER_RFF0_EN
|
||||
beq 1f
|
||||
|
||||
/* RX FIFO full? */
|
||||
ldr r13, [r12, #SSI_SISR]
|
||||
tst r13, #SSI_SISR_RFF0
|
||||
ldr r11, [r12, #SSI_SISR]
|
||||
tst r11, #SSI_SISR_RFF0
|
||||
beq 1f
|
||||
|
||||
ldr r11, imx_ssi_fiq_rx_buffer
|
||||
ldr r13, .L_imx_ssi_fiq_rx_buffer
|
||||
|
||||
mov r10, #0x10000
|
||||
sub r10, #1
|
||||
and r10, r10, r9 /* r10: current buffer offset */
|
||||
|
||||
add r11, r11, r10
|
||||
add r13, r13, r10
|
||||
|
||||
ldr r13, [r12, #SSI_SACNT]
|
||||
tst r13, #SSI_SACNT_AC97EN
|
||||
ldr r11, [r12, #SSI_SACNT]
|
||||
tst r11, #SSI_SACNT_AC97EN
|
||||
|
||||
ldr r13, [r12, #SSI_SRX0]
|
||||
strh r13, [r11]
|
||||
ldr r11, [r12, #SSI_SRX0]
|
||||
strh r11, [r13]
|
||||
|
||||
ldr r13, [r12, #SSI_SRX0]
|
||||
strh r13, [r11, #2]
|
||||
ldr r11, [r12, #SSI_SRX0]
|
||||
strh r11, [r13, #2]
|
||||
|
||||
/* dummy read to skip slot 12 */
|
||||
ldrne r13, [r12, #SSI_SRX0]
|
||||
ldrne r11, [r12, #SSI_SRX0]
|
||||
|
||||
ldr r13, [r12, #SSI_SRX0]
|
||||
strh r13, [r11, #4]
|
||||
ldr r11, [r12, #SSI_SRX0]
|
||||
strh r11, [r13, #4]
|
||||
|
||||
ldr r13, [r12, #SSI_SRX0]
|
||||
strh r13, [r11, #6]
|
||||
ldr r11, [r12, #SSI_SRX0]
|
||||
strh r11, [r13, #6]
|
||||
|
||||
/* dummy read to skip slot 12 */
|
||||
ldrne r13, [r12, #SSI_SRX0]
|
||||
ldrne r11, [r12, #SSI_SRX0]
|
||||
|
||||
add r10, #8
|
||||
lsr r13, r9, #16 /* r13: buffer size */
|
||||
cmp r10, r13
|
||||
lslgt r9, r13, #16
|
||||
lsr r11, r9, #16 /* r11: buffer size */
|
||||
cmp r10, r11
|
||||
lslgt r9, r11, #16
|
||||
addle r9, #8
|
||||
|
||||
1:
|
||||
|
@ -126,11 +133,15 @@ imx_ssi_fiq_start:
|
|||
subs pc, lr, #4
|
||||
|
||||
.align
|
||||
.L_imx_ssi_fiq_base:
|
||||
imx_ssi_fiq_base:
|
||||
.word 0x0
|
||||
.L_imx_ssi_fiq_rx_buffer:
|
||||
imx_ssi_fiq_rx_buffer:
|
||||
.word 0x0
|
||||
.L_imx_ssi_fiq_tx_buffer:
|
||||
imx_ssi_fiq_tx_buffer:
|
||||
.word 0x0
|
||||
.L_imx_ssi_fiq_end:
|
||||
imx_ssi_fiq_end:
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ extern struct dev_pm_domain omap_device_pm_domain;
|
|||
* @_dev_wakeup_lat_limit: dev wakeup latency limit in nsec - set by OMAP PM
|
||||
* @_state: one of OMAP_DEVICE_STATE_* (see above)
|
||||
* @flags: device flags
|
||||
* @_driver_status: one of BUS_NOTIFY_*_DRIVER from <linux/device.h>
|
||||
*
|
||||
* Integrates omap_hwmod data into Linux platform_device.
|
||||
*
|
||||
|
@ -73,6 +74,7 @@ struct omap_device {
|
|||
struct omap_device_pm_latency *pm_lats;
|
||||
u32 dev_wakeup_lat;
|
||||
u32 _dev_wakeup_lat_limit;
|
||||
unsigned long _driver_status;
|
||||
u8 pm_lats_cnt;
|
||||
s8 pm_lat_level;
|
||||
u8 hwmods_cnt;
|
||||
|
|
|
@ -659,6 +659,7 @@ extern int omap2420_hwmod_init(void);
|
|||
extern int omap2430_hwmod_init(void);
|
||||
extern int omap3xxx_hwmod_init(void);
|
||||
extern int omap44xx_hwmod_init(void);
|
||||
extern int am33xx_hwmod_init(void);
|
||||
|
||||
extern int __init omap_hwmod_register_links(struct omap_hwmod_ocp_if **ois);
|
||||
|
||||
|
|
|
@ -388,17 +388,21 @@ static int _omap_device_notifier_call(struct notifier_block *nb,
|
|||
unsigned long event, void *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct omap_device *od;
|
||||
|
||||
switch (event) {
|
||||
case BUS_NOTIFY_ADD_DEVICE:
|
||||
if (pdev->dev.of_node)
|
||||
omap_device_build_from_dt(pdev);
|
||||
break;
|
||||
|
||||
case BUS_NOTIFY_DEL_DEVICE:
|
||||
if (pdev->archdata.od)
|
||||
omap_device_delete(pdev->archdata.od);
|
||||
break;
|
||||
case BUS_NOTIFY_ADD_DEVICE:
|
||||
if (pdev->dev.of_node)
|
||||
omap_device_build_from_dt(pdev);
|
||||
/* fall through */
|
||||
default:
|
||||
od = to_omap_device(pdev);
|
||||
if (od)
|
||||
od->_driver_status = event;
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
|
@ -802,6 +806,10 @@ static int _od_suspend_noirq(struct device *dev)
|
|||
struct omap_device *od = to_omap_device(pdev);
|
||||
int ret;
|
||||
|
||||
/* Don't attempt late suspend on a driver that is not bound */
|
||||
if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER)
|
||||
return 0;
|
||||
|
||||
ret = pm_generic_suspend_noirq(dev);
|
||||
|
||||
if (!ret && !pm_runtime_status_suspended(dev)) {
|
||||
|
@ -1175,3 +1183,41 @@ static int __init omap_device_init(void)
|
|||
return 0;
|
||||
}
|
||||
core_initcall(omap_device_init);
|
||||
|
||||
/**
|
||||
* omap_device_late_idle - idle devices without drivers
|
||||
* @dev: struct device * associated with omap_device
|
||||
* @data: unused
|
||||
*
|
||||
* Check the driver bound status of this device, and idle it
|
||||
* if there is no driver attached.
|
||||
*/
|
||||
static int __init omap_device_late_idle(struct device *dev, void *data)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct omap_device *od = to_omap_device(pdev);
|
||||
|
||||
if (!od)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If omap_device state is enabled, but has no driver bound,
|
||||
* idle it.
|
||||
*/
|
||||
if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) {
|
||||
if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
|
||||
dev_warn(dev, "%s: enabled but no driver. Idling\n",
|
||||
__func__);
|
||||
omap_device_idle(pdev);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init omap_device_late_init(void)
|
||||
{
|
||||
bus_for_each_dev(&platform_bus_type, NULL, NULL, omap_device_late_idle);
|
||||
return 0;
|
||||
}
|
||||
late_initcall(omap_device_late_init);
|
||||
|
|
|
@ -152,4 +152,6 @@ source "drivers/vme/Kconfig"
|
|||
|
||||
source "drivers/pwm/Kconfig"
|
||||
|
||||
source "drivers/irqchip/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
# Rewritten to use lists instead of if-statements.
|
||||
#
|
||||
|
||||
obj-y += irqchip/
|
||||
|
||||
# GPIO must come after pinctrl as gpios may need to mux pins etc
|
||||
obj-y += pinctrl/
|
||||
obj-y += gpio/
|
||||
|
|
|
@ -3,6 +3,7 @@ obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
|
|||
obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \
|
||||
clk-mux.o clk-divider.o clk-fixed-factor.o
|
||||
# SoCs specific
|
||||
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
|
||||
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
|
||||
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
|
||||
obj-$(CONFIG_ARCH_MXS) += mxs/
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (C) 2010 Broadcom
|
||||
* Copyright (C) 2012 Stephen Warren
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk/bcm2835.h>
|
||||
|
||||
/*
|
||||
* These are fixed clocks. They're probably not all root clocks and it may
|
||||
* be possible to turn them on and off but until this is mapped out better
|
||||
* it's the only way they can be used.
|
||||
*/
|
||||
void __init bcm2835_init_clocks(void)
|
||||
{
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "sys_pclk", NULL, CLK_IS_ROOT,
|
||||
250000000);
|
||||
if (!clk)
|
||||
pr_err("sys_pclk not registered\n");
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT,
|
||||
126000000);
|
||||
if (!clk)
|
||||
pr_err("apb_pclk not registered\n");
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "uart0_pclk", NULL, CLK_IS_ROOT,
|
||||
3000000);
|
||||
if (!clk)
|
||||
pr_err("uart0_pclk not registered\n");
|
||||
ret = clk_register_clkdev(clk, NULL, "20201000.uart");
|
||||
if (ret)
|
||||
pr_err("uart0_pclk alias not registered\n");
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "uart1_pclk", NULL, CLK_IS_ROOT,
|
||||
125000000);
|
||||
if (!clk)
|
||||
pr_err("uart1_pclk not registered\n");
|
||||
ret = clk_register_clkdev(clk, NULL, "20215000.uart");
|
||||
if (ret)
|
||||
pr_err("uart0_pclk alias not registered\n");
|
||||
}
|
|
@ -13,3 +13,4 @@ obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o
|
|||
obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o
|
||||
obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
|
||||
obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o
|
||||
obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright 2012 Simon Arlott
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <linux/bcm2835_timer.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqreturn.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <asm/sched_clock.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#define REG_CONTROL 0x00
|
||||
#define REG_COUNTER_LO 0x04
|
||||
#define REG_COUNTER_HI 0x08
|
||||
#define REG_COMPARE(n) (0x0c + (n) * 4)
|
||||
#define MAX_TIMER 3
|
||||
#define DEFAULT_TIMER 3
|
||||
|
||||
struct bcm2835_timer {
|
||||
void __iomem *control;
|
||||
void __iomem *compare;
|
||||
int match_mask;
|
||||
struct clock_event_device evt;
|
||||
struct irqaction act;
|
||||
};
|
||||
|
||||
static void __iomem *system_clock __read_mostly;
|
||||
|
||||
static u32 notrace bcm2835_sched_read(void)
|
||||
{
|
||||
return readl_relaxed(system_clock);
|
||||
}
|
||||
|
||||
static void bcm2835_time_set_mode(enum clock_event_mode mode,
|
||||
struct clock_event_device *evt_dev)
|
||||
{
|
||||
switch (mode) {
|
||||
case CLOCK_EVT_MODE_ONESHOT:
|
||||
case CLOCK_EVT_MODE_UNUSED:
|
||||
case CLOCK_EVT_MODE_SHUTDOWN:
|
||||
case CLOCK_EVT_MODE_RESUME:
|
||||
break;
|
||||
default:
|
||||
WARN(1, "%s: unhandled event mode %d\n", __func__, mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int bcm2835_time_set_next_event(unsigned long event,
|
||||
struct clock_event_device *evt_dev)
|
||||
{
|
||||
struct bcm2835_timer *timer = container_of(evt_dev,
|
||||
struct bcm2835_timer, evt);
|
||||
writel_relaxed(readl_relaxed(system_clock) + event,
|
||||
timer->compare);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t bcm2835_time_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct bcm2835_timer *timer = dev_id;
|
||||
void (*event_handler)(struct clock_event_device *);
|
||||
if (readl_relaxed(timer->control) & timer->match_mask) {
|
||||
writel_relaxed(timer->match_mask, timer->control);
|
||||
|
||||
event_handler = ACCESS_ONCE(timer->evt.event_handler);
|
||||
if (event_handler)
|
||||
event_handler(&timer->evt);
|
||||
return IRQ_HANDLED;
|
||||
} else {
|
||||
return IRQ_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static struct of_device_id bcm2835_time_match[] __initconst = {
|
||||
{ .compatible = "brcm,bcm2835-system-timer" },
|
||||
{}
|
||||
};
|
||||
|
||||
static void __init bcm2835_time_init(void)
|
||||
{
|
||||
struct device_node *node;
|
||||
void __iomem *base;
|
||||
u32 freq;
|
||||
int irq;
|
||||
struct bcm2835_timer *timer;
|
||||
|
||||
node = of_find_matching_node(NULL, bcm2835_time_match);
|
||||
if (!node)
|
||||
panic("No bcm2835 timer node");
|
||||
|
||||
base = of_iomap(node, 0);
|
||||
if (!base)
|
||||
panic("Can't remap registers");
|
||||
|
||||
if (of_property_read_u32(node, "clock-frequency", &freq))
|
||||
panic("Can't read clock-frequency");
|
||||
|
||||
system_clock = base + REG_COUNTER_LO;
|
||||
setup_sched_clock(bcm2835_sched_read, 32, freq);
|
||||
|
||||
clocksource_mmio_init(base + REG_COUNTER_LO, node->name,
|
||||
freq, 300, 32, clocksource_mmio_readl_up);
|
||||
|
||||
irq = irq_of_parse_and_map(node, DEFAULT_TIMER);
|
||||
if (irq <= 0)
|
||||
panic("Can't parse IRQ");
|
||||
|
||||
timer = kzalloc(sizeof(*timer), GFP_KERNEL);
|
||||
if (!timer)
|
||||
panic("Can't allocate timer struct\n");
|
||||
|
||||
timer->control = base + REG_CONTROL;
|
||||
timer->compare = base + REG_COMPARE(DEFAULT_TIMER);
|
||||
timer->match_mask = BIT(DEFAULT_TIMER);
|
||||
timer->evt.name = node->name;
|
||||
timer->evt.rating = 300;
|
||||
timer->evt.features = CLOCK_EVT_FEAT_ONESHOT;
|
||||
timer->evt.set_mode = bcm2835_time_set_mode;
|
||||
timer->evt.set_next_event = bcm2835_time_set_next_event;
|
||||
timer->evt.cpumask = cpumask_of(0);
|
||||
timer->act.name = node->name;
|
||||
timer->act.flags = IRQF_TIMER | IRQF_SHARED;
|
||||
timer->act.dev_id = timer;
|
||||
timer->act.handler = bcm2835_time_interrupt;
|
||||
|
||||
if (setup_irq(irq, &timer->act))
|
||||
panic("Can't set up timer IRQ\n");
|
||||
|
||||
clockevents_config_and_register(&timer->evt, freq, 0xf, 0xffffffff);
|
||||
|
||||
pr_info("bcm2835: system timer (irq = %d)\n", irq);
|
||||
}
|
||||
|
||||
struct sys_timer bcm2835_timer = {
|
||||
.init = bcm2835_time_init,
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* Copyright 2010 Broadcom
|
||||
* Copyright 2012 Simon Arlott, Chris Boot, Stephen Warren
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Quirk 1: Shortcut interrupts don't set the bank 1/2 register pending bits
|
||||
*
|
||||
* If an interrupt fires on bank 1 that isn't in the shortcuts list, bit 8
|
||||
* on bank 0 is set to signify that an interrupt in bank 1 has fired, and
|
||||
* to look in the bank 1 status register for more information.
|
||||
*
|
||||
* If an interrupt fires on bank 1 that _is_ in the shortcuts list, its
|
||||
* shortcut bit in bank 0 is set as well as its interrupt bit in the bank 1
|
||||
* status register, but bank 0 bit 8 is _not_ set.
|
||||
*
|
||||
* Quirk 2: You can't mask the register 1/2 pending interrupts
|
||||
*
|
||||
* In a proper cascaded interrupt controller, the interrupt lines with
|
||||
* cascaded interrupt controllers on them are just normal interrupt lines.
|
||||
* You can mask the interrupts and get on with things. With this controller
|
||||
* you can't do that.
|
||||
*
|
||||
* Quirk 3: The shortcut interrupts can't be (un)masked in bank 0
|
||||
*
|
||||
* Those interrupts that have shortcuts can only be masked/unmasked in
|
||||
* their respective banks' enable/disable registers. Doing so in the bank 0
|
||||
* enable/disable registers has no effect.
|
||||
*
|
||||
* The FIQ control register:
|
||||
* Bits 0-6: IRQ (index in order of interrupts from banks 1, 2, then 0)
|
||||
* Bit 7: Enable FIQ generation
|
||||
* Bits 8+: Unused
|
||||
*
|
||||
* An interrupt must be disabled before configuring it for FIQ generation
|
||||
* otherwise both handlers will fire at the same time!
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/irqchip/bcm2835.h>
|
||||
|
||||
#include <asm/exception.h>
|
||||
|
||||
/* Put the bank and irq (32 bits) into the hwirq */
|
||||
#define MAKE_HWIRQ(b, n) ((b << 5) | (n))
|
||||
#define HWIRQ_BANK(i) (i >> 5)
|
||||
#define HWIRQ_BIT(i) BIT(i & 0x1f)
|
||||
|
||||
#define NR_IRQS_BANK0 8
|
||||
#define BANK0_HWIRQ_MASK 0xff
|
||||
/* Shortcuts can't be disabled so any unknown new ones need to be masked */
|
||||
#define SHORTCUT1_MASK 0x00007c00
|
||||
#define SHORTCUT2_MASK 0x001f8000
|
||||
#define SHORTCUT_SHIFT 10
|
||||
#define BANK1_HWIRQ BIT(8)
|
||||
#define BANK2_HWIRQ BIT(9)
|
||||
#define BANK0_VALID_MASK (BANK0_HWIRQ_MASK | BANK1_HWIRQ | BANK2_HWIRQ \
|
||||
| SHORTCUT1_MASK | SHORTCUT2_MASK)
|
||||
|
||||
#define REG_FIQ_CONTROL 0x0c
|
||||
|
||||
#define NR_BANKS 3
|
||||
#define IRQS_PER_BANK 32
|
||||
|
||||
static int reg_pending[] __initconst = { 0x00, 0x04, 0x08 };
|
||||
static int reg_enable[] __initconst = { 0x18, 0x10, 0x14 };
|
||||
static int reg_disable[] __initconst = { 0x24, 0x1c, 0x20 };
|
||||
static int bank_irqs[] __initconst = { 8, 32, 32 };
|
||||
|
||||
static const int shortcuts[] = {
|
||||
7, 9, 10, 18, 19, /* Bank 1 */
|
||||
21, 22, 23, 24, 25, 30 /* Bank 2 */
|
||||
};
|
||||
|
||||
struct armctrl_ic {
|
||||
void __iomem *base;
|
||||
void __iomem *pending[NR_BANKS];
|
||||
void __iomem *enable[NR_BANKS];
|
||||
void __iomem *disable[NR_BANKS];
|
||||
struct irq_domain *domain;
|
||||
};
|
||||
|
||||
static struct armctrl_ic intc __read_mostly;
|
||||
|
||||
static void armctrl_mask_irq(struct irq_data *d)
|
||||
{
|
||||
writel_relaxed(HWIRQ_BIT(d->hwirq), intc.disable[HWIRQ_BANK(d->hwirq)]);
|
||||
}
|
||||
|
||||
static void armctrl_unmask_irq(struct irq_data *d)
|
||||
{
|
||||
writel_relaxed(HWIRQ_BIT(d->hwirq), intc.enable[HWIRQ_BANK(d->hwirq)]);
|
||||
}
|
||||
|
||||
static struct irq_chip armctrl_chip = {
|
||||
.name = "ARMCTRL-level",
|
||||
.irq_mask = armctrl_mask_irq,
|
||||
.irq_unmask = armctrl_unmask_irq
|
||||
};
|
||||
|
||||
static int armctrl_xlate(struct irq_domain *d, struct device_node *ctrlr,
|
||||
const u32 *intspec, unsigned int intsize,
|
||||
unsigned long *out_hwirq, unsigned int *out_type)
|
||||
{
|
||||
if (WARN_ON(intsize != 2))
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN_ON(intspec[0] >= NR_BANKS))
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN_ON(intspec[1] >= IRQS_PER_BANK))
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN_ON(intspec[0] == 0 && intspec[1] >= NR_IRQS_BANK0))
|
||||
return -EINVAL;
|
||||
|
||||
*out_hwirq = MAKE_HWIRQ(intspec[0], intspec[1]);
|
||||
*out_type = IRQ_TYPE_NONE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_domain_ops armctrl_ops = {
|
||||
.xlate = armctrl_xlate
|
||||
};
|
||||
|
||||
static int __init armctrl_of_init(struct device_node *node,
|
||||
struct device_node *parent)
|
||||
{
|
||||
void __iomem *base;
|
||||
int irq, b, i;
|
||||
|
||||
base = of_iomap(node, 0);
|
||||
if (!base)
|
||||
panic("%s: unable to map IC registers\n",
|
||||
node->full_name);
|
||||
|
||||
intc.domain = irq_domain_add_linear(node, MAKE_HWIRQ(NR_BANKS, 0),
|
||||
&armctrl_ops, NULL);
|
||||
if (!intc.domain)
|
||||
panic("%s: unable to create IRQ domain\n", node->full_name);
|
||||
|
||||
for (b = 0; b < NR_BANKS; b++) {
|
||||
intc.pending[b] = base + reg_pending[b];
|
||||
intc.enable[b] = base + reg_enable[b];
|
||||
intc.disable[b] = base + reg_disable[b];
|
||||
|
||||
for (i = 0; i < bank_irqs[b]; i++) {
|
||||
irq = irq_create_mapping(intc.domain, MAKE_HWIRQ(b, i));
|
||||
BUG_ON(irq <= 0);
|
||||
irq_set_chip_and_handler(irq, &armctrl_chip,
|
||||
handle_level_irq);
|
||||
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id irq_of_match[] __initconst = {
|
||||
{ .compatible = "brcm,bcm2835-armctrl-ic", .data = armctrl_of_init }
|
||||
};
|
||||
|
||||
void __init bcm2835_init_irq(void)
|
||||
{
|
||||
of_irq_init(irq_of_match);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle each interrupt across the entire interrupt controller. This reads the
|
||||
* status register before handling each interrupt, which is necessary given that
|
||||
* handle_IRQ may briefly re-enable interrupts for soft IRQ handling.
|
||||
*/
|
||||
|
||||
static void armctrl_handle_bank(int bank, struct pt_regs *regs)
|
||||
{
|
||||
u32 stat, irq;
|
||||
|
||||
while ((stat = readl_relaxed(intc.pending[bank]))) {
|
||||
irq = MAKE_HWIRQ(bank, ffs(stat) - 1);
|
||||
handle_IRQ(irq_linear_revmap(intc.domain, irq), regs);
|
||||
}
|
||||
}
|
||||
|
||||
static void armctrl_handle_shortcut(int bank, struct pt_regs *regs,
|
||||
u32 stat)
|
||||
{
|
||||
u32 irq = MAKE_HWIRQ(bank, shortcuts[ffs(stat >> SHORTCUT_SHIFT) - 1]);
|
||||
handle_IRQ(irq_linear_revmap(intc.domain, irq), regs);
|
||||
}
|
||||
|
||||
asmlinkage void __exception_irq_entry bcm2835_handle_irq(
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
u32 stat, irq;
|
||||
|
||||
while ((stat = readl_relaxed(intc.pending[0]) & BANK0_VALID_MASK)) {
|
||||
if (stat & BANK0_HWIRQ_MASK) {
|
||||
irq = MAKE_HWIRQ(0, ffs(stat & BANK0_HWIRQ_MASK) - 1);
|
||||
handle_IRQ(irq_linear_revmap(intc.domain, irq), regs);
|
||||
} else if (stat & SHORTCUT1_MASK) {
|
||||
armctrl_handle_shortcut(1, regs, stat & SHORTCUT1_MASK);
|
||||
} else if (stat & SHORTCUT2_MASK) {
|
||||
armctrl_handle_shortcut(2, regs, stat & SHORTCUT2_MASK);
|
||||
} else if (stat & BANK1_HWIRQ) {
|
||||
armctrl_handle_bank(1, regs);
|
||||
} else if (stat & BANK2_HWIRQ) {
|
||||
armctrl_handle_bank(2, regs);
|
||||
} else {
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright 2012 Simon Arlott
|
||||
*
|
||||
* 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 __BCM2835_TIMER_H
|
||||
#define __BCM2835_TIMER_H
|
||||
|
||||
#include <asm/mach/time.h>
|
||||
|
||||
extern struct sys_timer bcm2835_timer;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (C) 2010 Broadcom
|
||||
*
|
||||
* 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 __LINUX_CLK_BCM2835_H_
|
||||
#define __LINUX_CLK_BCM2835_H_
|
||||
|
||||
void __init bcm2835_init_clocks(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (C) 2010 Broadcom
|
||||
*
|
||||
* 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 __LINUX_IRQCHIP_BCM2835_H_
|
||||
#define __LINUX_IRQCHIP_BCM2835_H_
|
||||
|
||||
#include <asm/exception.h>
|
||||
|
||||
extern void bcm2835_init_irq(void);
|
||||
|
||||
extern asmlinkage void __exception_irq_entry bcm2835_handle_irq(
|
||||
struct pt_regs *regs);
|
||||
|
||||
#endif
|
Загрузка…
Ссылка в новой задаче