diff options
Diffstat (limited to 'arch/arm')
115 files changed, 3124 insertions, 2853 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index fbdd8533c05..7980873525b 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -11,6 +11,7 @@ config ARM select RTC_LIB select SYS_SUPPORTS_APM_EMULATION select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI) + select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select HAVE_OPROFILE if (HAVE_PERF_EVENTS) select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL select HAVE_ARCH_KGDB @@ -38,6 +39,7 @@ config ARM select GENERIC_IRQ_PROBE select GENERIC_IRQ_SHOW select GENERIC_IRQ_PROBE + select ARCH_WANT_IPC_PARSE_VERSION select HARDIRQS_SW_RESEND select CPU_PM if (SUSPEND || CPU_IDLE) select GENERIC_PCI_IOMAP @@ -1009,7 +1011,6 @@ config ARCH_VT8500 select ARCH_HAS_CPUFREQ select GENERIC_CLOCKEVENTS select ARCH_REQUIRE_GPIOLIB - select HAVE_PWM help Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip. diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts index 2e1cfa00c25..9fecf1ae777 100644 --- a/arch/arm/boot/dts/highbank.dts +++ b/arch/arm/boot/dts/highbank.dts @@ -130,6 +130,12 @@ clocks = <&eclk>; }; + memory-controller@fff00000 { + compatible = "calxeda,hb-ddr-ctrl"; + reg = <0xfff00000 0x1000>; + interrupts = <0 91 4>; + }; + ipc@fff20000 { compatible = "arm,pl320", "arm,primecell"; reg = <0xfff20000 0x1000>; @@ -275,6 +281,12 @@ }; }; + sregs@fff3c200 { + compatible = "calxeda,hb-sregs-l2-ecc"; + reg = <0xfff3c200 0x100>; + interrupts = <0 71 4 0 72 4>; + }; + dma@fff3d000 { compatible = "arm,pl330", "arm,primecell"; reg = <0xfff3d000 0x1000>; diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index 915db89e364..787efac68da 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -660,6 +660,7 @@ compatible = "fsl,imx28-i2c"; reg = <0x80058000 2000>; interrupts = <111 68>; + clock-frequency = <100000>; status = "disabled"; }; @@ -669,6 +670,7 @@ compatible = "fsl,imx28-i2c"; reg = <0x8005a000 2000>; interrupts = <110 69>; + clock-frequency = <100000>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/r8a7740.dtsi b/arch/arm/boot/dts/r8a7740.dtsi new file mode 100644 index 00000000000..798fa35c000 --- /dev/null +++ b/arch/arm/boot/dts/r8a7740.dtsi @@ -0,0 +1,21 @@ +/* + * Device Tree Source for the r8a7740 SoC + * + * Copyright (C) 2012 Renesas Solutions Corp. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +/include/ "skeleton.dtsi" + +/ { + compatible = "renesas,r8a7740"; + + cpus { + cpu@0 { + compatible = "arm,cortex-a9"; + }; + }; +}; diff --git a/arch/arm/boot/dts/sh7377.dtsi b/arch/arm/boot/dts/sh7377.dtsi new file mode 100644 index 00000000000..767ee0796da --- /dev/null +++ b/arch/arm/boot/dts/sh7377.dtsi @@ -0,0 +1,21 @@ +/* + * Device Tree Source for the sh7377 SoC + * + * Copyright (C) 2012 Renesas Solutions Corp. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +/include/ "skeleton.dtsi" + +/ { + compatible = "renesas,sh7377"; + + cpus { + cpu@0 { + compatible = "arm,cortex-a8"; + }; + }; +}; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 9f1921634eb..405d1673904 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -123,6 +123,12 @@ status = "disabled"; }; + pwm { + compatible = "nvidia,tegra20-pwm"; + reg = <0x7000a000 0x100>; + #pwm-cells = <2>; + }; + i2c@7000c000 { compatible = "nvidia,tegra20-i2c"; reg = <0x7000c000 0x100>; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index da740191771..3e4334d14ef 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -117,6 +117,12 @@ status = "disabled"; }; + pwm { + compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm"; + reg = <0x7000a000 0x100>; + #pwm-cells = <2>; + }; + i2c@7000c000 { compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; reg = <0x7000c000 0x100>; diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index aa07f5938f0..1143c4d5c56 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -452,6 +452,7 @@ static struct dma_map_ops dmabounce_ops = { .alloc = arm_dma_alloc, .free = arm_dma_free, .mmap = arm_dma_mmap, + .get_sgtable = arm_dma_get_sgtable, .map_page = dmabounce_map_page, .unmap_page = dmabounce_unmap_page, .sync_single_for_cpu = dmabounce_sync_for_cpu, diff --git a/arch/arm/configs/armadillo800eva_defconfig b/arch/arm/configs/armadillo800eva_defconfig index ddc9fe6a78a..7d8718468e0 100644 --- a/arch/arm/configs/armadillo800eva_defconfig +++ b/arch/arm/configs/armadillo800eva_defconfig @@ -5,10 +5,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 # CONFIG_UTS_NS is not set # CONFIG_IPC_NS is not set -# CONFIG_USER_NS is not set # CONFIG_PID_NS is not set -CONFIG_SYSFS_DEPRECATED=y -CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SLAB=y CONFIG_MODULES=y @@ -21,7 +18,7 @@ CONFIG_ARCH_SHMOBILE=y CONFIG_ARCH_R8A7740=y CONFIG_MACH_ARMADILLO800EVA=y # CONFIG_SH_TIMER_TMU is not set -# CONFIG_ARM_THUMB is not set +CONFIG_ARM_THUMB=y CONFIG_CPU_BPREDICT_DISABLE=y # CONFIG_CACHE_L2X0 is not set CONFIG_ARM_ERRATA_430973=y @@ -39,6 +36,7 @@ CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_CMDLINE="console=tty0 console=ttySC1,115200 earlyprintk=sh-sci.1,115200 ignore_loglevel root=/dev/nfs ip=dhcp nfsroot=,rsize=4096,wsize=4096" CONFIG_CMDLINE_FORCE=y CONFIG_KEXEC=y +CONFIG_VFP=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set # CONFIG_SUSPEND is not set CONFIG_NET=y @@ -89,26 +87,32 @@ CONFIG_SERIAL_SH_SCI_CONSOLE=y CONFIG_I2C=y CONFIG_I2C_SH_MOBILE=y # CONFIG_HWMON is not set +CONFIG_MEDIA_SUPPORT=y +CONFIG_VIDEO_DEV=y +# CONFIG_RC_CORE is not set +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set +# CONFIG_V4L_USB_DRIVERS is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SOC_CAMERA=y +CONFIG_SOC_CAMERA_MT9T112=y +CONFIG_VIDEO_SH_MOBILE_CEU=y +# CONFIG_RADIO_ADAPTERS is not set CONFIG_FB=y -CONFIG_FB_MODE_HELPERS=y CONFIG_FB_SH_MOBILE_LCDC=y +CONFIG_FB_SH_MOBILE_HDMI=y CONFIG_LCD_CLASS_DEVICE=y CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set -CONFIG_SOUND=y -CONFIG_SND=y # CONFIG_SND_SUPPORT_OLD_API is not set # CONFIG_SND_VERBOSE_PROCFS is not set # CONFIG_SND_DRIVERS is not set # CONFIG_SND_ARM is not set -CONFIG_SND_SOC=y CONFIG_SND_SOC_SH4_FSI=y # CONFIG_HID_SUPPORT is not set CONFIG_USB=y -# CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_RENESAS_USBHS=y CONFIG_USB_GADGET=y CONFIG_USB_RENESAS_USBHS_UDC=y @@ -116,6 +120,8 @@ CONFIG_USB_ETH=m CONFIG_MMC=y CONFIG_MMC_SDHI=y CONFIG_MMC_SH_MMCIF=y +CONFIG_DMADEVICES=y +CONFIG_SH_DMAE=y CONFIG_UIO=y CONFIG_UIO_PDRV_GENIRQ=y # CONFIG_DNOTIFY is not set @@ -124,7 +130,6 @@ CONFIG_VFAT_FS=y CONFIG_TMPFS=y # CONFIG_MISC_FILESYSTEMS is not set CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V3_ACL=y CONFIG_NFS_V4=y CONFIG_NFS_V4_1=y diff --git a/arch/arm/configs/kzm9d_defconfig b/arch/arm/configs/kzm9d_defconfig new file mode 100644 index 00000000000..26146ffea1a --- /dev/null +++ b/arch/arm/configs/kzm9d_defconfig @@ -0,0 +1,89 @@ +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +CONFIG_EXPERIMENTAL=y +CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_EMBEDDED=y +CONFIG_SLAB=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_ARCH_SHMOBILE=y +CONFIG_ARCH_EMEV2=y +CONFIG_MACH_KZM9D=y +CONFIG_MEMORY_START=0x40000000 +CONFIG_MEMORY_SIZE=0x10000000 +# CONFIG_SH_TIMER_TMU is not set +# CONFIG_SWP_EMULATE is not set +# CONFIG_CACHE_L2X0 is not set +CONFIG_SMP=y +CONFIG_NR_CPUS=2 +CONFIG_HOTPLUG_CPU=y +# CONFIG_LOCAL_TIMERS is not set +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +# CONFIG_CROSS_MEMORY_ATTACH is not set +CONFIG_FORCE_MAX_ZONEORDER=13 +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_ARM_APPENDED_DTB=y +CONFIG_CMDLINE="console=tty0 console=ttyS1,115200n81 earlyprintk=serial8250-em.1,115200n81 mem=128M@0x40000000 ignore_loglevel root=/dev/nfs ip=dhcp nfsroot=,rsize=4096,wsize=4096" +CONFIG_CMDLINE_FORCE=y +CONFIG_VFP=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_SUSPEND is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_DIAG is not set +# CONFIG_IPV6 is not set +# CONFIG_WIRELESS is not set +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_BLK_DEV is not set +CONFIG_NETDEVICES=y +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_SEEQ is not set +CONFIG_SMSC911X=y +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_WLAN 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_LEGACY_PTYS is not set +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_EM=y +# CONFIG_HW_RANDOM is not set +CONFIG_GPIOLIB=y +CONFIG_GPIO_EM=y +# CONFIG_HWMON is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_IOMMU_SUPPORT is not set +# CONFIG_DNOTIFY is not set +CONFIG_TMPFS=y +# CONFIG_MISC_FILESYSTEMS is not set +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y +# CONFIG_FTRACE is not set diff --git a/arch/arm/configs/kzm9g_defconfig b/arch/arm/configs/kzm9g_defconfig index e3ebc20ed0a..2388c861062 100644 --- a/arch/arm/configs/kzm9g_defconfig +++ b/arch/arm/configs/kzm9g_defconfig @@ -100,7 +100,12 @@ CONFIG_SND_SOC_SH4_FSI=y CONFIG_USB=y CONFIG_USB_DEVICEFS=y CONFIG_USB_R8A66597_HCD=y +CONFIG_USB_RENESAS_USBHS=y CONFIG_USB_STORAGE=y +CONFIG_USB_GADGET=y +CONFIG_USB_RENESAS_USBHS_UDC=y +CONFIG_USB_ETH=m +CONFIG_USB_MASS_STORAGE=m CONFIG_MMC=y # CONFIG_MMC_BLOCK_BOUNCE is not set CONFIG_MMC_SDHI=y @@ -108,12 +113,13 @@ CONFIG_MMC_SH_MMCIF=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_RS5C372=y CONFIG_DMADEVICES=y CONFIG_SH_DMAE=y CONFIG_ASYNC_TX_DMA=y CONFIG_STAGING=y # CONFIG_DNOTIFY is not set -# CONFIG_INOTIFY_USER is not set +CONFIG_INOTIFY_USER=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y # CONFIG_MISC_FILESYSTEMS is not set diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index b152de79fd9..e58edc36b40 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -193,6 +193,8 @@ CONFIG_MMC_OMAP_HS=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_TWL92330=y CONFIG_RTC_DRV_TWL4030=y +CONFIG_DMADEVICES=y +CONFIG_DMA_OMAP=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_FS_XATTR is not set diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig index 4be9c1e80ee..db2245353f0 100644 --- a/arch/arm/configs/tegra_defconfig +++ b/arch/arm/configs/tegra_defconfig @@ -106,6 +106,7 @@ CONFIG_I2C_TEGRA=y CONFIG_SPI=y CONFIG_SPI_TEGRA=y CONFIG_GPIO_TPS65910=y +CONFIG_GPIO_TPS6586X=y CONFIG_POWER_SUPPLY=y CONFIG_BATTERY_SBS=y CONFIG_SENSORS_LM90=y diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 004c1bc95d2..e4448e16046 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -215,7 +215,9 @@ static inline void vivt_flush_cache_mm(struct mm_struct *mm) static inline void vivt_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { - if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) + struct mm_struct *mm = vma->vm_mm; + + if (!mm || cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm))) __cpuc_flush_user_range(start & PAGE_MASK, PAGE_ALIGN(end), vma->vm_flags); } @@ -223,7 +225,9 @@ vivt_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned static inline void vivt_flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn) { - if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) { + struct mm_struct *mm = vma->vm_mm; + + if (!mm || cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm))) { unsigned long addr = user_addr & PAGE_MASK; __cpuc_flush_user_range(addr, addr + PAGE_SIZE, vma->vm_flags); } diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index bbef15d0489..2ae842df455 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -186,17 +186,6 @@ extern int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma, void *cpu_addr, dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs); -#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, NULL) - -static inline int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, - void *cpu_addr, dma_addr_t dma_addr, - size_t size, struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - BUG_ON(!ops); - return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs); -} - static inline void *dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) { @@ -213,20 +202,12 @@ static inline void dma_free_writecombine(struct device *dev, size_t size, return dma_free_attrs(dev, size, cpu_addr, dma_handle, &attrs); } -static inline int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma, - void *cpu_addr, dma_addr_t dma_addr, size_t size) -{ - DEFINE_DMA_ATTRS(attrs); - dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); - return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, &attrs); -} - /* * This can be called during boot to increase the size of the consistent * DMA region above it's default value of 2MB. It must be called before the * memory allocator is initialised, i.e. before any core_initcall. */ -extern void __init init_consistent_dma_size(unsigned long size); +static inline void init_consistent_dma_size(unsigned long size) { } /* * For SA-1111, IXP425, and ADI systems the dma-mapping functions are "magic" @@ -280,6 +261,9 @@ extern void arm_dma_sync_sg_for_cpu(struct device *, struct scatterlist *, int, enum dma_data_direction); extern void arm_dma_sync_sg_for_device(struct device *, struct scatterlist *, int, enum dma_data_direction); +extern int arm_dma_get_sgtable(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t dma_addr, size_t size, + struct dma_attrs *attrs); #endif /* __KERNEL__ */ #endif diff --git a/arch/arm/include/asm/mutex.h b/arch/arm/include/asm/mutex.h index 93226cf23ae..b1479fd04a9 100644 --- a/arch/arm/include/asm/mutex.h +++ b/arch/arm/include/asm/mutex.h @@ -7,121 +7,10 @@ */ #ifndef _ASM_MUTEX_H #define _ASM_MUTEX_H - -#if __LINUX_ARM_ARCH__ < 6 -/* On pre-ARMv6 hardware the swp based implementation is the most efficient. */ -# include <asm-generic/mutex-xchg.h> -#else - /* - * Attempting to lock a mutex on ARMv6+ can be done with a bastardized - * atomic decrement (it is not a reliable atomic decrement but it satisfies - * the defined semantics for our purpose, while being smaller and faster - * than a real atomic decrement or atomic swap. The idea is to attempt - * decrementing the lock value only once. If once decremented it isn't zero, - * or if its store-back fails due to a dispute on the exclusive store, we - * simply bail out immediately through the slow path where the lock will be - * reattempted until it succeeds. + * On pre-ARMv6 hardware this results in a swp-based implementation, + * which is the most efficient. For ARMv6+, we emit a pair of exclusive + * accesses instead. */ -static inline void -__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *)) -{ - int __ex_flag, __res; - - __asm__ ( - - "ldrex %0, [%2] \n\t" - "sub %0, %0, #1 \n\t" - "strex %1, %0, [%2] " - - : "=&r" (__res), "=&r" (__ex_flag) - : "r" (&(count)->counter) - : "cc","memory" ); - - __res |= __ex_flag; - if (unlikely(__res != 0)) - fail_fn(count); -} - -static inline int -__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *)) -{ - int __ex_flag, __res; - - __asm__ ( - - "ldrex %0, [%2] \n\t" - "sub %0, %0, #1 \n\t" - "strex %1, %0, [%2] " - - : "=&r" (__res), "=&r" (__ex_flag) - : "r" (&(count)->counter) - : "cc","memory" ); - - __res |= __ex_flag; - if (unlikely(__res != 0)) - __res = fail_fn(count); - return __res; -} - -/* - * Same trick is used for the unlock fast path. However the original value, - * rather than the result, is used to test for success in order to have - * better generated assembly. - */ -static inline void -__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *)) -{ - int __ex_flag, __res, __orig; - - __asm__ ( - - "ldrex %0, [%3] \n\t" - "add %1, %0, #1 \n\t" - "strex %2, %1, [%3] " - - : "=&r" (__orig), "=&r" (__res), "=&r" (__ex_flag) - : "r" (&(count)->counter) - : "cc","memory" ); - - __orig |= __ex_flag; - if (unlikely(__orig != 0)) - fail_fn(count); -} - -/* - * If the unlock was done on a contended lock, or if the unlock simply fails - * then the mutex remains locked. - */ -#define __mutex_slowpath_needs_to_unlock() 1 - -/* - * For __mutex_fastpath_trylock we use another construct which could be - * described as a "single value cmpxchg". - * - * This provides the needed trylock semantics like cmpxchg would, but it is - * lighter and less generic than a true cmpxchg implementation. - */ -static inline int -__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) -{ - int __ex_flag, __res, __orig; - - __asm__ ( - - "1: ldrex %0, [%3] \n\t" - "subs %1, %0, #1 \n\t" - "strexeq %2, %1, [%3] \n\t" - "movlt %0, #0 \n\t" - "cmpeq %2, #0 \n\t" - "bgt 1b " - - : "=&r" (__orig), "=&r" (__res), "=&r" (__ex_flag) - : "r" (&count->counter) - : "cc", "memory" ); - - return __orig; -} - -#endif +#include <asm-generic/mutex-xchg.h> #endif diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h index 23ebc0c82a3..24d284a1bfc 100644 --- a/arch/arm/include/asm/setup.h +++ b/arch/arm/include/asm/setup.h @@ -196,7 +196,7 @@ static const struct tagtable __tagtable_##fn __tag = { tag, fn } struct membank { phys_addr_t start; - unsigned long size; + phys_addr_t size; unsigned int highmem; }; @@ -217,7 +217,7 @@ extern struct meminfo meminfo; #define bank_phys_end(bank) ((bank)->start + (bank)->size) #define bank_phys_size(bank) (bank)->size -extern int arm_add_memory(phys_addr_t start, unsigned long size); +extern int arm_add_memory(phys_addr_t start, phys_addr_t size); extern void early_print(const char *str, ...); extern void dump_machine_table(void); diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h index 512cd147345..0cab47d4a83 100644 --- a/arch/arm/include/asm/unistd.h +++ b/arch/arm/include/asm/unistd.h @@ -446,7 +446,6 @@ #ifdef __KERNEL__ -#define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_GETHOSTNAME #define __ARCH_WANT_SYS_PAUSE diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 0d1851ca6eb..0f82098c9bf 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -244,6 +244,19 @@ svc_preempt: b 1b #endif +__und_fault: + @ Correct the PC such that it is pointing at the instruction + @ which caused the fault. If the faulting instruction was ARM + @ the PC will be pointing at the next instruction, and have to + @ subtract 4. Otherwise, it is Thumb, and the PC will be + @ pointing at the second half of the Thumb instruction. We + @ have to subtract 2. + ldr r2, [r0, #S_PC] + sub r2, r2, r1 + str r2, [r0, #S_PC] + b do_undefinstr +ENDPROC(__und_fault) + .align 5 __und_svc: #ifdef CONFIG_KPROBES @@ -261,25 +274,32 @@ __und_svc: @ @ r0 - instruction @ -#ifndef CONFIG_THUMB2_KERNEL +#ifndef CONFIG_THUMB2_KERNEL ldr r0, [r4, #-4] #else + mov r1, #2 ldrh r0, [r4, #-2] @ Thumb instruction at LR - 2 cmp r0, #0xe800 @ 32-bit instruction if xx >= 0 - ldrhhs r9, [r4] @ bottom 16 bits - orrhs r0, r9, r0, lsl #16 + blo __und_svc_fault + ldrh r9, [r4] @ bottom 16 bits + add r4, r4, #2 + str r4, [sp, #S_PC] + orr r0, r9, r0, lsl #16 #endif - adr r9, BSYM(1f) + adr r9, BSYM(__und_svc_finish) mov r2, r4 bl call_fpe + mov r1, #4 @ PC correction to apply +__und_svc_fault: mov r0, sp @ struct pt_regs *regs - bl do_undefinstr + bl __und_fault @ @ IRQs off again before pulling preserved data off the stack @ -1: disable_irq_notrace +__und_svc_finish: + disable_irq_notrace @ @ restore SPSR and restart the instruction @@ -423,25 +443,33 @@ __und_usr: mov r2, r4 mov r3, r5 + @ r2 = regs->ARM_pc, which is either 2 or 4 bytes ahead of the + @ faulting instruction depending on Thumb mode. + @ r3 = regs->ARM_cpsr @ - @ fall through to the emulation code, which returns using r9 if - @ it has emulated the instruction, or the more conventional lr - @ if we are to treat this as a real undefined instruction - @ - @ r0 - instruction + @ The emulation code returns using r9 if it has emulated the + @ instruction, or the more conventional lr if we are to treat + @ this as a real undefined instruction @ adr r9, BSYM(ret_from_exception) - adr lr, BSYM(__und_usr_unknown) + tst r3, #PSR_T_BIT @ Thumb mode? - itet eq @ explicit IT needed for the 1f label - subeq r4, r2, #4 @ ARM instr at LR - 4 - subne r4, r2, #2 @ Thumb instr at LR - 2 -1: ldreqt r0, [r4] + bne __und_usr_thumb + sub r4, r2, #4 @ ARM instr at LR - 4 +1: ldrt r0, [r4] #ifdef CONFIG_CPU_ENDIAN_BE8 - reveq r0, r0 @ little endian instruction + rev r0, r0 @ little endian instruction #endif - beq call_fpe + @ r0 = 32-bit ARM instruction which caused the exception + @ r2 = PC value for the following instruction (:= regs->ARM_pc) + @ r4 = PC value for the faulting instruction + @ lr = 32-bit undefined instruction function + adr lr, BSYM(__und_usr_fault_32) + b call_fpe + +__und_usr_thumb: @ Thumb instruction + sub r4, r2, #2 @ First half of thumb instr at LR - 2 #if CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7 /* * Thumb-2 instruction handling. Note that because pre-v6 and >= v6 platforms @@ -455,7 +483,7 @@ __und_usr: ldr r5, .LCcpu_architecture ldr r5, [r5] cmp r5, #CPU_ARCH_ARMv7 - blo __und_usr_unknown + blo __und_usr_fault_16 @ 16bit undefined instruction /* * The following code won't get run unless the running CPU really is v7, so * coding round the lack of ldrht on older arches is pointless. Temporarily @@ -463,15 +491,18 @@ __und_usr: */ .arch armv6t2 #endif -2: - ARM( ldrht r5, [r4], #2 ) - THUMB( ldrht r5, [r4] ) - THUMB( add r4, r4, #2 ) +2: ldrht r5, [r4] cmp r5, #0xe800 @ 32bit instruction if xx != 0 - blo __und_usr_unknown -3: ldrht r0, [r4] + blo __und_usr_fault_16 @ 16bit undefined instruction +3: ldrht r0, [r2] add r2, r2, #2 @ r2 is PC + 2, make it PC + 4 + str r2, [sp, #S_PC] @ it's a 2x16bit instr, update orr r0, r0, r5, lsl #16 + adr lr, BSYM(__und_usr_fault_32) + @ r0 = the two 16-bit Thumb instructions which caused the exception + @ r2 = PC value for the following Thumb instruction (:= regs->ARM_pc) + @ r4 = PC value for the first 16-bit Thumb instruction + @ lr = 32bit undefined instruction function #if __LINUX_ARM_ARCH__ < 7 /* If the target arch was overridden, change it back: */ @@ -482,17 +513,13 @@ __und_usr: #endif #endif /* __LINUX_ARM_ARCH__ < 7 */ #else /* !(CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7) */ - b __und_usr_unknown + b __und_usr_fault_16 #endif - UNWIND(.fnend ) + UNWIND(.fnend) ENDPROC(__und_usr) - @ - @ fallthrough to call_fpe - @ - /* - * The out of line fixup for the ldrt above. + * The out of line fixup for the ldrt instructions above. */ .pushsection .fixup, "ax" .align 2 @@ -524,11 +551,12 @@ ENDPROC(__und_usr) * NEON handler code. * * Emulators may wish to make use of the following registers: - * r0 = instruction opcode. - * r2 = PC+4 + * r0 = instruction opcode (32-bit ARM or two 16-bit Thumb) + * r2 = PC value to resume execution after successful emulation * r9 = normal "successful" return address - * r10 = this threads thread_info structure. + * r10 = this threads thread_info structure * lr = unrecognised instruction return address + * IRQs disabled, FIQs enabled. */ @ @ Fall-through from Thumb-2 __und_usr @@ -659,12 +687,17 @@ ENTRY(no_fp) mov pc, lr ENDPROC(no_fp) -__und_usr_unknown: - enable_irq +__und_usr_fault_32: + mov r1, #4 + b 1f +__und_usr_fault_16: + mov r1, #2 +1: enable_irq mov r0, sp adr lr, BSYM(ret_from_exception) - b do_undefinstr -ENDPROC(__und_usr_unknown) + b __und_fault +ENDPROC(__und_usr_fault_32) +ENDPROC(__und_usr_fault_16) .align 5 __pabt_usr: diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 49d9f930524..978eac57e04 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -51,23 +51,15 @@ ret_fast_syscall: fast_work_pending: str r0, [sp, #S_R0+S_OFF]! @ returned r0 work_pending: - tst r1, #_TIF_NEED_RESCHED - bne work_resched - /* - * TIF_SIGPENDING or TIF_NOTIFY_RESUME must've been set if we got here - */ - ldr r2, [sp, #S_PSR] mov r0, sp @ 'regs' - tst r2, #15 @ are we returning to user mode? - bne no_work_pending @ no? just leave, then... mov r2, why @ 'syscall' - tst r1, #_TIF_SIGPENDING @ delivering a signal? - movne why, #0 @ prevent further restarts - bl do_notify_resume - b ret_slow_syscall @ Check work again + bl do_work_pending + cmp r0, #0 + beq no_work_pending + movlt scno, #(__NR_restart_syscall - __NR_SYSCALL_BASE) + ldmia sp, {r0 - r6} @ have to reload r0 - r6 + b local_restart @ ... and off we go -work_resched: - bl schedule /* * "slow" syscall return path. "why" tells us if this was a real syscall. */ @@ -409,6 +401,7 @@ ENTRY(vector_swi) eor scno, scno, #__NR_SYSCALL_BASE @ check OS number #endif +local_restart: ldr r10, [tsk, #TI_FLAGS] @ check for syscall tracing stmdb sp!, {r4, r5} @ push fifth and sixth args @@ -450,7 +443,8 @@ __sys_trace: mov scno, r0 @ syscall number (possibly new) add r1, sp, #S_R0 + S_OFF @ pointer to regs cmp scno, #NR_syscalls @ check upper syscall limit - ldmccia r1, {r0 - r3} @ have to reload r0 - r3 + ldmccia r1, {r0 - r6} @ have to reload r0 - r6 + stmccia sp, {r4, r5} @ and update the stack args ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine b 2b diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index df0bf0c8cb7..34e56647dce 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c @@ -179,19 +179,20 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, old = *parent; *parent = return_hooker; - err = ftrace_push_return_trace(old, self_addr, &trace.depth, - frame_pointer); - if (err == -EBUSY) { - *parent = old; - return; - } - trace.func = self_addr; + trace.depth = current->curr_ret_stack + 1; /* Only trace if the calling function expects to */ if (!ftrace_graph_entry(&trace)) { - current->curr_ret_stack--; *parent = old; + return; + } + + err = ftrace_push_return_trace(old, self_addr, &trace.depth, + frame_pointer); + if (err == -EBUSY) { + *parent = old; + return; } } diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 19c95ea65b2..693b744fd57 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -247,6 +247,7 @@ void machine_shutdown(void) void machine_halt(void) { machine_shutdown(); + local_irq_disable(); while (1); } @@ -268,6 +269,7 @@ void machine_restart(char *cmd) /* Whoops - the platform was unable to reboot. Tell the user! */ printk("Reboot failed -- System halted\n"); + local_irq_disable(); while (1); } diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index dab711e6e1c..3e0fc5f7ed4 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -25,6 +25,7 @@ #include <linux/regset.h> #include <linux/audit.h> #include <linux/tracehook.h> +#include <linux/unistd.h> #include <asm/pgtable.h> #include <asm/traps.h> diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index e15d83bb4ea..a81dcecc734 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -508,7 +508,7 @@ void __init dump_machine_table(void) /* can't use cpu_relax() here as it may require MMU setup */; } -int __init arm_add_memory(phys_addr_t start, unsigned long size) +int __init arm_add_memory(phys_addr_t start, phys_addr_t size) { struct membank *bank = &meminfo.bank[meminfo.nr_banks]; @@ -538,7 +538,7 @@ int __init arm_add_memory(phys_addr_t start, unsigned long size) } #endif - bank->size = size & PAGE_MASK; + bank->size = size & ~(phys_addr_t)(PAGE_SIZE - 1); /* * Check whether this memory region has non-zero size or @@ -558,7 +558,7 @@ int __init arm_add_memory(phys_addr_t start, unsigned long size) static int __init early_mem(char *p) { static int usermem __initdata = 0; - unsigned long size; + phys_addr_t size; phys_addr_t start; char *endp; diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 536c5d6b340..f27789e4e38 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -27,7 +27,6 @@ */ #define SWI_SYS_SIGRETURN (0xef000000|(__NR_sigreturn)|(__NR_OABI_SYSCALL_BASE)) #define SWI_SYS_RT_SIGRETURN (0xef000000|(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE)) -#define SWI_SYS_RESTART (0xef000000|__NR_restart_syscall|__NR_OABI_SYSCALL_BASE) /* * With EABI, the syscall number has to be loaded into r7. @@ -48,18 +47,6 @@ const unsigned long sigreturn_codes[7] = { }; /* - * Either we support OABI only, or we have EABI with the OABI - * compat layer enabled. In the later case we don't know if - * user space is EABI or not, and if not we must not clobber r7. - * Always using the OABI syscall solves that issue and works for - * all those cases. - */ -const unsigned long syscall_restart_code[2] = { - SWI_SYS_RESTART, /* swi __NR_restart_syscall */ - 0xe49df004, /* ldr pc, [sp], #4 */ -}; - -/* * atomically swap in the new signal mask, and wait for a signal. */ asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask) @@ -582,12 +569,13 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ -static void do_signal(struct pt_regs *regs, int syscall) +static int do_signal(struct pt_regs *regs, int syscall) { unsigned int retval = 0, continue_addr = 0, restart_addr = 0; struct k_sigaction ka; siginfo_t info; int signr; + int restart = 0; /* * If we were from a system call, check for system call restarting... @@ -602,15 +590,15 @@ static void do_signal(struct pt_regs *regs, int syscall) * debugger will see the already changed PSW. */ switch (retval) { + case -ERESTART_RESTARTBLOCK: + restart -= 2; case -ERESTARTNOHAND: case -ERESTARTSYS: case -ERESTARTNOINTR: + restart++; regs->ARM_r0 = regs->ARM_ORIG_r0; regs->ARM_pc = restart_addr; break; - case -ERESTART_RESTARTBLOCK: - regs->ARM_r0 = -EINTR; - break; } } @@ -619,14 +607,17 @@ static void do_signal(struct pt_regs *regs, int syscall) * point the debugger may change all our registers ... */ signr = get_signal_to_deliver(&info, &ka, regs, NULL); + /* + * Depending on the signal settings we may need to revert the + * decision to restart the system call. But skip this if a + * debugger has chosen to restart at a different PC. + */ + if (regs->ARM_pc != restart_addr) + restart = 0; if (signr > 0) { - /* - * Depending on the signal settings we may need to revert the - * decision to restart the system call. But skip this if a - * debugger has chosen to restart at a different PC. - */ - if (regs->ARM_pc == restart_addr) { - if (retval == -ERESTARTNOHAND + if (unlikely(restart)) { + if (retval == -ERESTARTNOHAND || + retval == -ERESTART_RESTARTBLOCK || (retval == -ERESTARTSYS && !(ka.sa.sa_flags & SA_RESTART))) { regs->ARM_r0 = -EINTR; @@ -635,52 +626,43 @@ static void do_signal(struct pt_regs *regs, int syscall) } handle_signal(signr, &ka, &info, regs); - return; - } - - if (syscall) { - /* - * Handle restarting a different system call. As above, - * if a debugger has chosen to restart at a different PC, - * ignore the restart. - */ - if (retval == -ERESTART_RESTARTBLOCK - && regs->ARM_pc == continue_addr) { - if (thumb_mode(regs)) { - regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE; - regs->ARM_pc -= 2; - } else { -#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT) - regs->ARM_r7 = __NR_restart_syscall; - regs->ARM_pc -= 4; -#else - u32 __user *usp; - - regs->ARM_sp -= 4; - usp = (u32 __user *)regs->ARM_sp; - - if (put_user(regs->ARM_pc, usp) == 0) { - regs->ARM_pc = KERN_RESTART_CODE; - } else { - regs->ARM_sp += 4; - force_sigsegv(0, current); - } -#endif - } - } + return 0; } restore_saved_sigmask(); + if (unlikely(restart)) + regs->ARM_pc = continue_addr; + return restart; } -asmlinkage void -do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall) +asmlinkage int +do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall) { - if (thread_flags & _TIF_SIGPENDING) - do_signal(regs, syscall); - - if (thread_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); - } + do { + if (likely(thread_flags & _TIF_NEED_RESCHED)) { + schedule(); + } else { + if (unlikely(!user_mode(regs))) + return 0; + local_irq_enable(); + if (thread_flags & _TIF_SIGPENDING) { + int restart = do_signal(regs, syscall); + if (unlikely(restart)) { + /* + * Restart without handlers. + * Deal with it without leaving + * the kernel space. + */ + return restart; + } + syscall = 0; + } else { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); + } + } + local_irq_disable(); + thread_flags = current_thread_info()->flags; + } while (thread_flags & _TIF_WORK_MASK); + return 0; } diff --git a/arch/arm/kernel/signal.h b/arch/arm/kernel/signal.h index 6fcfe8398aa..5ff067b7c75 100644 --- a/arch/arm/kernel/signal.h +++ b/arch/arm/kernel/signal.h @@ -8,7 +8,5 @@ * published by the Free Software Foundation. */ #define KERN_SIGRETURN_CODE (CONFIG_VECTORS_BASE + 0x00000500) -#define KERN_RESTART_CODE (KERN_SIGRETURN_CODE + sizeof(sigreturn_codes)) extern const unsigned long sigreturn_codes[7]; -extern const unsigned long syscall_restart_code[2]; diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index aea74f5bc34..ebd8ad274d7 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -563,7 +563,8 @@ void smp_send_stop(void) cpumask_copy(&mask, cpu_online_mask); cpumask_clear_cpu(smp_processor_id(), &mask); - smp_cross_call(&mask, IPI_CPU_STOP); + if (!cpumask_empty(&mask)) + smp_cross_call(&mask, IPI_CPU_STOP); /* Wait up to one second for other CPUs to stop */ timeout = USEC_PER_SEC; diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 8b97d739b17..f7945218b8c 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -402,18 +402,10 @@ static int call_undef_hook(struct pt_regs *regs, unsigned int instr) asmlinkage void __exception do_undefinstr(struct pt_regs *regs) { - unsigned int correction = thumb_mode(regs) ? 2 : 4; unsigned int instr; siginfo_t info; void __user *pc; - /* - * According to the ARM ARM, PC is 2 or 4 bytes ahead, - * depending whether we're in Thumb mode or not. - * Correct this offset. - */ - regs->ARM_pc -= correction; - pc = (void __user *)instruction_pointer(regs); if (processor_mode(regs) == SVC_MODE) { @@ -852,8 +844,6 @@ void __init early_trap_init(void *vectors_base) */ memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE), sigreturn_codes, sizeof(sigreturn_codes)); - memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE), - syscall_restart_code, sizeof(syscall_restart_code)); flush_icache_range(vectors, vectors + PAGE_SIZE); modify_domain(DOMAIN_USER, DOMAIN_CLIENT); diff --git a/arch/arm/lib/io-acorn.S b/arch/arm/lib/io-acorn.S index 1b197ea7aab..69719bad674 100644 --- a/arch/arm/lib/io-acorn.S +++ b/arch/arm/lib/io-acorn.S @@ -11,13 +11,14 @@ * */ #include <linux/linkage.h> +#include <linux/kern_levels.h> #include <asm/assembler.h> .text .align .Liosl_warning: - .ascii "<4>insl/outsl not implemented, called from %08lX\0" + .ascii KERN_WARNING "insl/outsl not implemented, called from %08lX\0" .align /* diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index d1624a315c9..783eab6845c 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -546,6 +546,7 @@ static struct lcd_ctrl_config lcd_cfg = { .sync_edge = 0, .sync_ctrl = 1, .raster_order = 0, + .fifo_th = 6, }; struct da8xx_lcdc_platform_data sharp_lcd035q3dg01_pdata = { diff --git a/arch/arm/mach-exynos/clock-exynos4.c b/arch/arm/mach-exynos/clock-exynos4.c index 26fe9de35ec..2f51293c187 100644 --- a/arch/arm/mach-exynos/clock-exynos4.c +++ b/arch/arm/mach-exynos/clock-exynos4.c @@ -620,10 +620,6 @@ static struct clk exynos4_init_clocks_off[] = { .enable = exynos4_clk_ip_peril_ctrl, .ctrlbit = (1 << 27), }, { - .name = "fimg2d", - .enable = exynos4_clk_ip_image_ctrl, - .ctrlbit = (1 << 0), - }, { .name = "mfc", .devname = "s5p-mfc", .enable = exynos4_clk_ip_mfc_ctrl, @@ -819,47 +815,21 @@ static struct clk *exynos4_clkset_mout_g2d0_list[] = { [1] = &exynos4_clk_sclk_apll.clk, }; -static struct clksrc_sources exynos4_clkset_mout_g2d0 = { +struct clksrc_sources exynos4_clkset_mout_g2d0 = { .sources = exynos4_clkset_mout_g2d0_list, .nr_sources = ARRAY_SIZE(exynos4_clkset_mout_g2d0_list), }; -static struct clksrc_clk exynos4_clk_mout_g2d0 = { - .clk = { - .name = "mout_g2d0", - }, - .sources = &exynos4_clkset_mout_g2d0, - .reg_src = { .reg = EXYNOS4_CLKSRC_IMAGE, .shift = 0, .size = 1 }, -}; - static struct clk *exynos4_clkset_mout_g2d1_list[] = { [0] = &exynos4_clk_mout_epll.clk, [1] = &exynos4_clk_sclk_vpll.clk, }; -static struct clksrc_sources exynos4_clkset_mout_g2d1 = { +struct clksrc_sources exynos4_clkset_mout_g2d1 = { .sources = exynos4_clkset_mout_g2d1_list, .nr_sources = ARRAY_SIZE(exynos4_clkset_mout_g2d1_list), }; -static struct clksrc_clk exynos4_clk_mout_g2d1 = { - .clk = { - .name = "mout_g2d1", - }, - .sources = &exynos4_clkset_mout_g2d1, - .reg_src = { .reg = EXYNOS4_CLKSRC_IMAGE, .shift = 4, .size = 1 }, -}; - -static struct clk *exynos4_clkset_mout_g2d_list[] = { - [0] = &exynos4_clk_mout_g2d0.clk, - [1] = &exynos4_clk_mout_g2d1.clk, -}; - -static struct clksrc_sources exynos4_clkset_mout_g2d = { - .sources = exynos4_clkset_mout_g2d_list, - .nr_sources = ARRAY_SIZE(exynos4_clkset_mout_g2d_list), -}; - static struct clk *exynos4_clkset_mout_mfc0_list[] = { [0] = &exynos4_clk_mout_mpll.clk, [1] = &exynos4_clk_sclk_apll.clk, @@ -1126,13 +1096,6 @@ static struct clksrc_clk exynos4_clksrcs[] = { .reg_div = { .reg = EXYNOS4_CLKDIV_LCD0, .shift = 0, .size = 4 }, }, { .clk = { - .name = "sclk_fimg2d", - }, - .sources = &exynos4_clkset_mout_g2d, - .reg_src = { .reg = EXYNOS4_CLKSRC_IMAGE, .shift = 8, .size = 1 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_IMAGE, .shift = 0, .size = 4 }, - }, { - .clk = { .name = "sclk_mfc", .devname = "s5p-mfc", }, diff --git a/arch/arm/mach-exynos/clock-exynos4.h b/arch/arm/mach-exynos/clock-exynos4.h index 28a11970118..bd12d5f8b63 100644 --- a/arch/arm/mach-exynos/clock-exynos4.h +++ b/arch/arm/mach-exynos/clock-exynos4.h @@ -23,6 +23,9 @@ extern struct clksrc_sources exynos4_clkset_group; extern struct clk *exynos4_clkset_aclk_top_list[]; extern struct clk *exynos4_clkset_group_list[]; +extern struct clksrc_sources exynos4_clkset_mout_g2d0; +extern struct clksrc_sources exynos4_clkset_mout_g2d1; + extern int exynos4_clksrc_mask_fsys_ctrl(struct clk *clk, int enable); extern int exynos4_clk_ip_fsys_ctrl(struct clk *clk, int enable); extern int exynos4_clk_ip_lcd1_ctrl(struct clk *clk, int enable); diff --git a/arch/arm/mach-exynos/clock-exynos4210.c b/arch/arm/mach-exynos/clock-exynos4210.c index b8689ff60ba..fed4c26e9da 100644 --- a/arch/arm/mach-exynos/clock-exynos4210.c +++ b/arch/arm/mach-exynos/clock-exynos4210.c @@ -48,6 +48,32 @@ static struct clksrc_clk *sysclks[] = { /* nothing here yet */ }; +static struct clksrc_clk exynos4210_clk_mout_g2d0 = { + .clk = { + .name = "mout_g2d0", + }, + .sources = &exynos4_clkset_mout_g2d0, + .reg_src = { .reg = EXYNOS4_CLKSRC_IMAGE, .shift = 0, .size = 1 }, +}; + +static struct clksrc_clk exynos4210_clk_mout_g2d1 = { + .clk = { + .name = "mout_g2d1", + }, + .sources = &exynos4_clkset_mout_g2d1, + .reg_src = { .reg = EXYNOS4_CLKSRC_IMAGE, .shift = 4, .size = 1 }, +}; + +static struct clk *exynos4210_clkset_mout_g2d_list[] = { + [0] = &exynos4210_clk_mout_g2d0.clk, + [1] = &exynos4210_clk_mout_g2d1.clk, +}; + +static struct clksrc_sources exynos4210_clkset_mout_g2d = { + .sources = exynos4210_clkset_mout_g2d_list, + .nr_sources = ARRAY_SIZE(exynos4210_clkset_mout_g2d_list), +}; + static int exynos4_clksrc_mask_lcd1_ctrl(struct clk *clk, int enable) { return s5p_gatectrl(EXYNOS4210_CLKSRC_MASK_LCD1, clk, enable); @@ -74,6 +100,13 @@ static struct clksrc_clk clksrcs[] = { .sources = &exynos4_clkset_group, .reg_src = { .reg = EXYNOS4210_CLKSRC_LCD1, .shift = 0, .size = 4 }, .reg_div = { .reg = EXYNOS4210_CLKDIV_LCD1, .shift = 0, .size = 4 }, + }, { + .clk = { + .name = "sclk_fimg2d", + }, + .sources = &exynos4210_clkset_mout_g2d, + .reg_src = { .reg = EXYNOS4_CLKSRC_IMAGE, .shift = 8, .size = 1 }, + .reg_div = { .reg = EXYNOS4_CLKDIV_IMAGE, .shift = 0, .size = 4 }, }, }; @@ -105,6 +138,10 @@ static struct clk init_clocks_off[] = { .devname = SYSMMU_CLOCK_DEVNAME(fimd1, 11), .enable = exynos4_clk_ip_lcd1_ctrl, .ctrlbit = (1 << 4), + }, { + .name = "fimg2d", + .enable = exynos4_clk_ip_image_ctrl, + .ctrlbit = (1 << 0), }, }; diff --git a/arch/arm/mach-exynos/clock-exynos4212.c b/arch/arm/mach-exynos/clock-exynos4212.c index da397d21bbc..8fba0b5fb8a 100644 --- a/arch/arm/mach-exynos/clock-exynos4212.c +++ b/arch/arm/mach-exynos/clock-exynos4212.c @@ -68,12 +68,45 @@ static struct clksrc_clk clk_mout_mpll_user = { .reg_src = { .reg = EXYNOS4_CLKSRC_CPU, .shift = 24, .size = 1 }, }; +static struct clksrc_clk exynos4x12_clk_mout_g2d0 = { + .clk = { + .name = "mout_g2d0", + }, + .sources = &exynos4_clkset_mout_g2d0, + .reg_src = { .reg = EXYNOS4_CLKSRC_DMC, .shift = 20, .size = 1 }, +}; + +static struct clksrc_clk exynos4x12_clk_mout_g2d1 = { + .clk = { + .name = "mout_g2d1", + }, + .sources = &exynos4_clkset_mout_g2d1, + .reg_src = { .reg = EXYNOS4_CLKSRC_DMC, .shift = 24, .size = 1 }, +}; + +static struct clk *exynos4x12_clkset_mout_g2d_list[] = { + [0] = &exynos4x12_clk_mout_g2d0.clk, + [1] = &exynos4x12_clk_mout_g2d1.clk, +}; + +static struct clksrc_sources exynos4x12_clkset_mout_g2d = { + .sources = exynos4x12_clkset_mout_g2d_list, + .nr_sources = ARRAY_SIZE(exynos4x12_clkset_mout_g2d_list), +}; + static struct clksrc_clk *sysclks[] = { &clk_mout_mpll_user, }; static struct clksrc_clk clksrcs[] = { - /* nothing here yet */ + { + .clk = { + .name = "sclk_fimg2d", + }, + .sources = &exynos4x12_clkset_mout_g2d, + .reg_src = { .reg = EXYNOS4_CLKSRC_DMC, .shift = 28, .size = 1 }, + .reg_div = { .reg = EXYNOS4_CLKDIV_DMC1, .shift = 0, .size = 4 }, + }, }; static struct clk init_clocks_off[] = { @@ -102,7 +135,11 @@ static struct clk init_clocks_off[] = { .devname = "exynos-fimc-lite.1", .enable = exynos4212_clk_ip_isp0_ctrl, .ctrlbit = (1 << 3), - } + }, { + .name = "fimg2d", + .enable = exynos4_clk_ip_dmc_ctrl, + .ctrlbit = (1 << 23), + }, }; #ifdef CONFIG_PM_SLEEP diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c index f98a83a81ce..ea785fcaf6c 100644 --- a/arch/arm/mach-exynos/mach-nuri.c +++ b/arch/arm/mach-exynos/mach-nuri.c @@ -1066,12 +1066,8 @@ static struct platform_device nuri_max8903_device = { static void __init nuri_power_init(void) { int gpio; - int irq_base = IRQ_GPIO_END + 1; int ta_en = 0; - nuri_max8997_pdata.irq_base = irq_base; - irq_base += MAX8997_IRQ_NR; - gpio = EXYNOS4_GPX0(7); gpio_request(gpio, "AP_PMIC_IRQ"); s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0xf)); diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c index 5a12dc26f49..5ca80307d6d 100644 --- a/arch/arm/mach-exynos/mach-origen.c +++ b/arch/arm/mach-exynos/mach-origen.c @@ -426,7 +426,6 @@ static struct max8997_platform_data __initdata origen_max8997_pdata = { .buck1_gpiodvs = false, .buck2_gpiodvs = false, .buck5_gpiodvs = false, - .irq_base = IRQ_GPIO_END + 1, .ignore_gpiodvs_side_effect = true, .buck125_default_idx = 0x0, diff --git a/arch/arm/mach-netx/fb.c b/arch/arm/mach-netx/fb.c index 2cdf6ef69be..d122ee6ab99 100644 --- a/arch/arm/mach-netx/fb.c +++ b/arch/arm/mach-netx/fb.c @@ -69,29 +69,6 @@ void netx_clcd_remove(struct clcd_fb *fb) fb->fb.screen_base, fb->fb.fix.smem_start); } -void clk_disable(struct clk *clk) -{ -} - -int clk_set_rate(struct clk *clk, unsigned long rate) -{ - return 0; -} - -int clk_enable(struct clk *clk) -{ - return 0; -} - -struct clk *clk_get(struct device *dev, const char *id) -{ - return dev && strcmp(dev_name(dev), "fb") == 0 ? NULL : ERR_PTR(-ENOENT); -} - -void clk_put(struct clk *clk) -{ -} - static AMBA_AHB_DEVICE(fb, "fb", 0, 0x00104000, { NETX_IRQ_LCD }, NULL); int netx_fb_init(struct clcd_board *board, struct clcd_panel *panel) diff --git a/arch/arm/mach-omap1/board-h2-mmc.c b/arch/arm/mach-omap1/board-h2-mmc.c index da0e37d4082..e1362ce4849 100644 --- a/arch/arm/mach-omap1/board-h2-mmc.c +++ b/arch/arm/mach-omap1/board-h2-mmc.c @@ -54,7 +54,6 @@ static struct omap_mmc_platform_data mmc1_data = { .nr_slots = 1, .init = mmc_late_init, .cleanup = mmc_cleanup, - .dma_mask = 0xffffffff, .slots[0] = { .set_power = mmc_set_power, .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, diff --git a/arch/arm/mach-omap1/board-h3-mmc.c b/arch/arm/mach-omap1/board-h3-mmc.c index f8242aa9b76..c74daace8cd 100644 --- a/arch/arm/mach-omap1/board-h3-mmc.c +++ b/arch/arm/mach-omap1/board-h3-mmc.c @@ -36,7 +36,6 @@ static int mmc_set_power(struct device *dev, int slot, int power_on, */ static struct omap_mmc_platform_data mmc1_data = { .nr_slots = 1, - .dma_mask = 0xffffffff, .slots[0] = { .set_power = mmc_set_power, .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c index 4007a372481..2c0ca8fc338 100644 --- a/arch/arm/mach-omap1/board-nokia770.c +++ b/arch/arm/mach-omap1/board-nokia770.c @@ -185,7 +185,6 @@ static int nokia770_mmc_get_cover_state(struct device *dev, int slot) static struct omap_mmc_platform_data nokia770_mmc2_data = { .nr_slots = 1, - .dma_mask = 0xffffffff, .max_freq = 12000000, .slots[0] = { .set_power = nokia770_mmc_set_power, diff --git a/arch/arm/mach-omap1/board-palmz71.c b/arch/arm/mach-omap1/board-palmz71.c index cc71a26723e..355980321c2 100644 --- a/arch/arm/mach-omap1/board-palmz71.c +++ b/arch/arm/mach-omap1/board-palmz71.c @@ -288,8 +288,7 @@ palmz71_gpio_setup(int early) } gpio_direction_input(PALMZ71_USBDETECT_GPIO); if (request_irq(gpio_to_irq(PALMZ71_USBDETECT_GPIO), - palmz71_powercable, IRQF_SAMPLE_RANDOM, - "palmz71-cable", NULL)) + palmz71_powercable, 0, "palmz71-cable", NULL)) printk(KERN_ERR "IRQ request for power cable failed!\n"); palmz71_powercable(gpio_to_irq(PALMZ71_USBDETECT_GPIO), NULL); diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c index 2c5d0ed7528..677357ff61a 100644 --- a/arch/arm/mach-omap2/board-n8x0.c +++ b/arch/arm/mach-omap2/board-n8x0.c @@ -468,7 +468,6 @@ static struct omap_mmc_platform_data mmc1_data = { .cleanup = n8x0_mmc_cleanup, .shutdown = n8x0_mmc_shutdown, .max_freq = 24000000, - .dma_mask = 0xffffffff, .slots[0] = { .wires = 4, .set_power = n8x0_mmc_set_power, diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c index 5fb47a14f4b..af1ed7d24a1 100644 --- a/arch/arm/mach-omap2/display.c +++ b/arch/arm/mach-omap2/display.c @@ -37,6 +37,7 @@ #define DISPC_CONTROL 0x0040 #define DISPC_CONTROL2 0x0238 +#define DISPC_CONTROL3 0x0848 #define DISPC_IRQSTATUS 0x0018 #define DSS_SYSCONFIG 0x10 @@ -52,6 +53,7 @@ #define EVSYNC_EVEN_IRQ_SHIFT 2 #define EVSYNC_ODD_IRQ_SHIFT 3 #define FRAMEDONE2_IRQ_SHIFT 22 +#define FRAMEDONE3_IRQ_SHIFT 30 #define FRAMEDONETV_IRQ_SHIFT 24 /* @@ -376,7 +378,7 @@ int __init omap_display_init(struct omap_dss_board_info *board_data) static void dispc_disable_outputs(void) { u32 v, irq_mask = 0; - bool lcd_en, digit_en, lcd2_en = false; + bool lcd_en, digit_en, lcd2_en = false, lcd3_en = false; int i; struct omap_dss_dispc_dev_attr *da; struct omap_hwmod *oh; @@ -405,7 +407,13 @@ static void dispc_disable_outputs(void) lcd2_en = v & LCD_EN_MASK; } - if (!(lcd_en | digit_en | lcd2_en)) + /* store value of LCDENABLE for LCD3 */ + if (da->manager_count > 3) { + v = omap_hwmod_read(oh, DISPC_CONTROL3); + lcd3_en = v & LCD_EN_MASK; + } + + if (!(lcd_en | digit_en | lcd2_en | lcd3_en)) return; /* no managers currently enabled */ /* @@ -426,10 +434,12 @@ static void dispc_disable_outputs(void) if (lcd2_en) irq_mask |= 1 << FRAMEDONE2_IRQ_SHIFT; + if (lcd3_en) + irq_mask |= 1 << FRAMEDONE3_IRQ_SHIFT; /* * clear any previous FRAMEDONE, FRAMEDONETV, - * EVSYNC_EVEN/ODD or FRAMEDONE2 interrupts + * EVSYNC_EVEN/ODD, FRAMEDONE2 or FRAMEDONE3 interrupts */ omap_hwmod_write(irq_mask, oh, DISPC_IRQSTATUS); @@ -445,12 +455,19 @@ static void dispc_disable_outputs(void) omap_hwmod_write(v, oh, DISPC_CONTROL2); } + /* disable LCD3 manager */ + if (da->manager_count > 3) { + v = omap_hwmod_read(oh, DISPC_CONTROL3); + v &= ~LCD_EN_MASK; + omap_hwmod_write(v, oh, DISPC_CONTROL3); + } + i = 0; while ((omap_hwmod_read(oh, DISPC_IRQSTATUS) & irq_mask) != irq_mask) { i++; if (i > FRAMEDONE_IRQ_TIMEOUT) { - pr_err("didn't get FRAMEDONE1/2 or TV interrupt\n"); + pr_err("didn't get FRAMEDONE1/2/3 or TV interrupt\n"); break; } mdelay(1); diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index be697d4e084..a9675d8d182 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -315,7 +315,6 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, mmc->slots[0].caps = c->caps; mmc->slots[0].pm_caps = c->pm_caps; mmc->slots[0].internal_clock = !c->ext_clock; - mmc->dma_mask = 0xffffffff; mmc->max_freq = c->max_freq; if (cpu_is_omap44xx()) mmc->reg_offset = OMAP4_MMC_REG_OFFSET; diff --git a/arch/arm/mach-pxa/eseries.h b/arch/arm/mach-pxa/eseries.h deleted file mode 100644 index b96949dd5ad..00000000000 --- a/arch/arm/mach-pxa/eseries.h +++ /dev/null @@ -1,14 +0,0 @@ -void __init eseries_fixup(struct tag *tags, char **cmdline, struct meminfo *mi); - -extern struct pxa2xx_udc_mach_info e7xx_udc_mach_info; -extern struct pxaficp_platform_data e7xx_ficp_platform_data; -extern int e7xx_irda_init(void); - -extern int eseries_tmio_enable(struct platform_device *dev); -extern int eseries_tmio_disable(struct platform_device *dev); -extern int eseries_tmio_suspend(struct platform_device *dev); -extern int eseries_tmio_resume(struct platform_device *dev); -extern void eseries_get_tmio_gpios(void); -extern struct resource eseries_tmio_resources[]; -extern struct platform_device e300_tc6387xb_device; - diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c index d3de84b0dcb..e6311988add 100644 --- a/arch/arm/mach-pxa/hx4700.c +++ b/arch/arm/mach-pxa/hx4700.c @@ -296,27 +296,11 @@ static struct asic3_led asic3_leds[ASIC3_NUM_LEDS] = { static struct resource asic3_resources[] = { /* GPIO part */ - [0] = { - .start = ASIC3_PHYS, - .end = ASIC3_PHYS + ASIC3_MAP_SIZE_16BIT - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = PXA_GPIO_TO_IRQ(GPIO12_HX4700_ASIC3_IRQ), - .end = PXA_GPIO_TO_IRQ(GPIO12_HX4700_ASIC3_IRQ), - .flags = IORESOURCE_IRQ, - }, + [0] = DEFINE_RES_MEM(ASIC3_PHYS, ASIC3_MAP_SIZE_16BIT), + [1] = DEFINE_RES_IRQ(PXA_GPIO_TO_IRQ(GPIO12_HX4700_ASIC3_IRQ)), /* SD part */ - [2] = { - .start = ASIC3_SD_PHYS, - .end = ASIC3_SD_PHYS + ASIC3_MAP_SIZE_16BIT - 1, - .flags = IORESOURCE_MEM, - }, - [3] = { - .start = PXA_GPIO_TO_IRQ(GPIO66_HX4700_ASIC3_nSDIO_IRQ), - .end = PXA_GPIO_TO_IRQ(GPIO66_HX4700_ASIC3_nSDIO_IRQ), - .flags = IORESOURCE_IRQ, - }, + [2] = DEFINE_RES_MEM(ASIC3_SD_PHYS, ASIC3_MAP_SIZE_16BIT), + [3] = DEFINE_RES_IRQ(PXA_GPIO_TO_IRQ(GPIO66_HX4700_ASIC3_nSDIO_IRQ)), }; static struct asic3_platform_data asic3_platform_data = { @@ -343,11 +327,7 @@ static struct platform_device asic3 = { */ static struct resource egpio_resources[] = { - [0] = { - .start = PXA_CS5_PHYS, - .end = PXA_CS5_PHYS + 0x4 - 1, - .flags = IORESOURCE_MEM, - }, + [0] = DEFINE_RES_MEM(PXA_CS5_PHYS, 0x4), }; static struct htc_egpio_chip egpio_chips[] = { @@ -537,11 +517,7 @@ static struct w100fb_mach_info w3220_info = { }; static struct resource w3220_resources[] = { - [0] = { - .start = ATI_W3220_PHYS, - .end = ATI_W3220_PHYS + 0x00ffffff, - .flags = IORESOURCE_MEM, - }, + [0] = DEFINE_RES_MEM(ATI_W3220_PHYS, SZ_16M), }; static struct platform_device w3220 = { @@ -683,20 +659,12 @@ static struct pda_power_pdata power_supply_info = { }; static struct resource power_supply_resources[] = { - [0] = { - .name = "ac", - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE | - IORESOURCE_IRQ_LOWEDGE, - .start = PXA_GPIO_TO_IRQ(GPIOD9_nAC_IN), - .end = PXA_GPIO_TO_IRQ(GPIOD9_nAC_IN), - }, - [1] = { - .name = "usb", - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE | - IORESOURCE_IRQ_LOWEDGE, - .start = PXA_GPIO_TO_IRQ(GPIOD14_nUSBC_DETECT), - .end = PXA_GPIO_TO_IRQ(GPIOD14_nUSBC_DETECT), - }, + [0] = DEFINE_RES_NAMED(PXA_GPIO_TO_IRQ(GPIOD9_nAC_IN), 1, "ac", + IORESOURCE_IRQ | + IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE), + [1] = DEFINE_RES_NAMED(PXA_GPIO_TO_IRQ(GPIOD14_nUSBC_DETECT), 1, "usb", + IORESOURCE_IRQ | + IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE), }; static struct platform_device power_supply = { diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 6bb3f47b1f1..0ca0db78790 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -456,7 +456,7 @@ static int lubbock_mci_init(struct device *dev, init_timer(&mmc_timer); mmc_timer.data = (unsigned long) data; return request_irq(LUBBOCK_SD_IRQ, lubbock_detect_int, - IRQF_SAMPLE_RANDOM, "lubbock-sd-detect", data); + 0, "lubbock-sd-detect", data); } static int lubbock_mci_get_ro(struct device *dev) diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c index 2db697cd2b4..39561dcf65f 100644 --- a/arch/arm/mach-pxa/magician.c +++ b/arch/arm/mach-pxa/magician.c @@ -633,9 +633,8 @@ static struct platform_device bq24022 = { static int magician_mci_init(struct device *dev, irq_handler_t detect_irq, void *data) { - return request_irq(IRQ_MAGICIAN_SD, detect_irq, - IRQF_DISABLED | IRQF_SAMPLE_RANDOM, - "mmc card detect", data); + return request_irq(IRQ_MAGICIAN_SD, detect_irq, IRQF_DISABLED, + "mmc card detect", data); } static void magician_mci_exit(struct device *dev, void *data) diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c index 2b6ac00b2cd..166dd32cc1d 100644 --- a/arch/arm/mach-pxa/trizeps4.c +++ b/arch/arm/mach-pxa/trizeps4.c @@ -332,8 +332,8 @@ static int trizeps4_mci_init(struct device *dev, irq_handler_t mci_detect_int, int err; err = request_irq(TRIZEPS4_MMC_IRQ, mci_detect_int, - IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_SAMPLE_RANDOM, - "MMC card detect", data); + IRQF_DISABLED | IRQF_TRIGGER_RISING, + "MMC card detect", data); if (err) { printk(KERN_ERR "trizeps4_mci_init: MMC/SD: can't request" "MMC card detect IRQ\n"); diff --git a/arch/arm/mach-s3c64xx/include/mach/pm-core.h b/arch/arm/mach-s3c64xx/include/mach/pm-core.h index fcf3dcabb69..c0537f40a3d 100644 --- a/arch/arm/mach-s3c64xx/include/mach/pm-core.h +++ b/arch/arm/mach-s3c64xx/include/mach/pm-core.h @@ -12,6 +12,9 @@ * published by the Free Software Foundation. */ +#ifndef __MACH_S3C64XX_PM_CORE_H +#define __MACH_S3C64XX_PM_CORE_H __FILE__ + #include <mach/regs-gpio.h> static inline void s3c_pm_debug_init_uart(void) @@ -113,3 +116,4 @@ static inline void samsung_pm_saved_gpios(void) __raw_writel(S3C64XX_SLPEN_USE_xSLP, S3C64XX_SLPEN); } +#endif /* __MACH_S3C64XX_PM_CORE_H */ diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index df33909205e..4cacc2d22fb 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -19,6 +19,7 @@ config ARCH_SH7372 select CPU_V7 select SH_CLK_CPG select ARCH_WANT_OPTIONAL_GPIOLIB + select ARM_CPU_SUSPEND if PM || CPU_IDLE config ARCH_SH73A0 bool "SH-Mobile AG5 (R8A73A00)" @@ -58,6 +59,7 @@ config MACH_G4EVM bool "G4EVM board" depends on ARCH_SH7377 select ARCH_REQUIRE_GPIOLIB + select REGULATOR_FIXED_VOLTAGE if REGULATOR config MACH_AP4EVB bool "AP4EVB board" @@ -65,6 +67,7 @@ config MACH_AP4EVB select ARCH_REQUIRE_GPIOLIB select SH_LCD_MIPI_DSI select SND_SOC_AK4642 if SND_SIMPLE_CARD + select REGULATOR_FIXED_VOLTAGE if REGULATOR choice prompt "AP4EVB LCD panel selection" @@ -83,6 +86,7 @@ config MACH_AG5EVM bool "AG5EVM board" select ARCH_REQUIRE_GPIOLIB select SH_LCD_MIPI_DSI + select REGULATOR_FIXED_VOLTAGE if REGULATOR depends on ARCH_SH73A0 config MACH_MACKEREL @@ -90,15 +94,18 @@ config MACH_MACKEREL depends on ARCH_SH7372 select ARCH_REQUIRE_GPIOLIB select SND_SOC_AK4642 if SND_SIMPLE_CARD + select REGULATOR_FIXED_VOLTAGE if REGULATOR config MACH_KOTA2 bool "KOTA2 board" select ARCH_REQUIRE_GPIOLIB + select REGULATOR_FIXED_VOLTAGE if REGULATOR depends on ARCH_SH73A0 config MACH_BONITO bool "bonito board" select ARCH_REQUIRE_GPIOLIB + select REGULATOR_FIXED_VOLTAGE if REGULATOR depends on ARCH_R8A7740 config MACH_ARMADILLO800EVA @@ -106,22 +113,28 @@ config MACH_ARMADILLO800EVA depends on ARCH_R8A7740 select ARCH_REQUIRE_GPIOLIB select USE_OF + select REGULATOR_FIXED_VOLTAGE if REGULATOR + select SND_SOC_WM8978 if SND_SIMPLE_CARD config MACH_MARZEN bool "MARZEN board" depends on ARCH_R8A7779 select ARCH_REQUIRE_GPIOLIB + select REGULATOR_FIXED_VOLTAGE if REGULATOR config MACH_KZM9D bool "KZM9D board" depends on ARCH_EMEV2 select USE_OF + select REGULATOR_FIXED_VOLTAGE if REGULATOR config MACH_KZM9G bool "KZM-A9-GT board" depends on ARCH_SH73A0 select ARCH_REQUIRE_GPIOLIB select USE_OF + select SND_SOC_AK4642 if SND_SIMPLE_CARD + select REGULATOR_FIXED_VOLTAGE if REGULATOR comment "SH-Mobile System Configuration" diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index 8aa1962c22a..0df5ae6740c 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -39,7 +39,9 @@ obj-$(CONFIG_ARCH_R8A7740) += entry-intc.o # PM objects obj-$(CONFIG_SUSPEND) += suspend.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o +obj-$(CONFIG_ARCH_SHMOBILE) += pm-rmobile.o obj-$(CONFIG_ARCH_SH7372) += pm-sh7372.o sleep-sh7372.o +obj-$(CONFIG_ARCH_R8A7740) += pm-r8a7740.o obj-$(CONFIG_ARCH_R8A7779) += pm-r8a7779.o # Board objects diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c index 5a6f22f05e9..d82c010fdfc 100644 --- a/arch/arm/mach-shmobile/board-ag5evm.c +++ b/arch/arm/mach-shmobile/board-ag5evm.c @@ -27,6 +27,8 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/dma-mapping.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/serial_sci.h> #include <linux/smsc911x.h> #include <linux/gpio.h> @@ -52,6 +54,12 @@ #include <asm/hardware/cache-l2x0.h> #include <asm/traps.h> +/* Dummy supplies, where voltage doesn't matter */ +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vddvario", "smsc911x"), + REGULATOR_SUPPLY("vdd33a", "smsc911x"), +}; + static struct resource smsc9220_resources[] = { [0] = { .start = 0x14000000, @@ -142,6 +150,13 @@ static struct platform_device fsi_device = { .resource = fsi_resources, }; +/* Fixed 1.8V regulator to be used by MMCIF */ +static struct regulator_consumer_supply fixed1v8_power_consumers[] = +{ + REGULATOR_SUPPLY("vmmc", "sh_mmcif.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mmcif.0"), +}; + static struct resource sh_mmcif_resources[] = { [0] = { .name = "MMCIF", @@ -364,6 +379,13 @@ static struct platform_device mipidsi0_device = { }, }; +/* Fixed 2.8V regulators to be used by SDHI0 */ +static struct regulator_consumer_supply fixed2v8_power_consumers[] = +{ + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"), +}; + /* SDHI0 */ static struct sh_mobile_sdhi_info sdhi0_info = { .dma_slave_tx = SHDMA_SLAVE_SDHI0_TX, @@ -408,8 +430,57 @@ static struct platform_device sdhi0_device = { }, }; -void ag5evm_sdhi1_set_pwr(struct platform_device *pdev, int state) +/* Fixed 3.3V regulator to be used by SDHI1 */ +static struct regulator_consumer_supply cn4_power_consumers[] = { + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.1"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.1"), +}; + +static struct regulator_init_data cn4_power_init_data = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(cn4_power_consumers), + .consumer_supplies = cn4_power_consumers, +}; + +static struct fixed_voltage_config cn4_power_info = { + .supply_name = "CN4 SD/MMC Vdd", + .microvolts = 3300000, + .gpio = GPIO_PORT114, + .enable_high = 1, + .init_data = &cn4_power_init_data, +}; + +static struct platform_device cn4_power = { + .name = "reg-fixed-voltage", + .id = 2, + .dev = { + .platform_data = &cn4_power_info, + }, +}; + +static void ag5evm_sdhi1_set_pwr(struct platform_device *pdev, int state) +{ + static int power_gpio = -EINVAL; + + if (power_gpio < 0) { + int ret = gpio_request(GPIO_PORT114, "sdhi1_power"); + if (!ret) { + power_gpio = GPIO_PORT114; + gpio_direction_output(power_gpio, 0); + } + } + + /* + * If requesting the GPIO above failed, it means, that the regulator got + * probed and grabbed the GPIO, but we don't know, whether the sdhi + * driver already uses the regulator. If it doesn't, we have to toggle + * the GPIO ourselves, even though it is now owned by the fixed + * regulator driver. We have to live with the race in case the driver + * gets unloaded and the GPIO freed between these two steps. + */ gpio_set_value(GPIO_PORT114, state); } @@ -455,6 +526,7 @@ static struct platform_device sdhi1_device = { }; static struct platform_device *ag5evm_devices[] __initdata = { + &cn4_power, ð_device, &keysc_device, &fsi_device, @@ -468,6 +540,12 @@ static struct platform_device *ag5evm_devices[] __initdata = { static void __init ag5evm_init(void) { + regulator_register_always_on(0, "fixed-1.8V", fixed1v8_power_consumers, + ARRAY_SIZE(fixed1v8_power_consumers), 1800000); + regulator_register_always_on(1, "fixed-2.8V", fixed2v8_power_consumers, + ARRAY_SIZE(fixed2v8_power_consumers), 3300000); + regulator_register_fixed(3, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + sh73a0_pinmux_init(); /* enable SCIFA2 */ @@ -562,8 +640,6 @@ static void __init ag5evm_init(void) gpio_request(GPIO_FN_SDHID1_2_PU, NULL); gpio_request(GPIO_FN_SDHID1_1_PU, NULL); gpio_request(GPIO_FN_SDHID1_0_PU, NULL); - gpio_request(GPIO_PORT114, "sdhi1_power"); - gpio_direction_output(GPIO_PORT114, 0); #ifdef CONFIG_CACHE_L2X0 /* Shared attribute override enable, 64K*8way */ diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index ace60246a5d..f172ca85905 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -34,6 +34,8 @@ #include <linux/i2c.h> #include <linux/i2c/tsc2007.h> #include <linux/io.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/smsc911x.h> #include <linux/sh_intc.h> #include <linux/sh_clk.h> @@ -159,6 +161,27 @@ * CN12: 3.3v */ +/* Dummy supplies, where voltage doesn't matter */ +static struct regulator_consumer_supply fixed1v8_power_consumers[] = +{ + /* J22 default position: 1.8V */ + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.1"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.1"), + REGULATOR_SUPPLY("vmmc", "sh_mmcif.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mmcif.0"), +}; + +static struct regulator_consumer_supply fixed3v3_power_consumers[] = +{ + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"), +}; + +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vddvario", "smsc911x"), + REGULATOR_SUPPLY("vdd33a", "smsc911x"), +}; + /* MTD */ static struct mtd_partition nor_flash_partitions[] = { { @@ -1138,21 +1161,6 @@ static void __init fsi_init_pm_clock(void) clk_put(fsia_ick); } -/* - * FIXME !! - * - * gpio_no_direction - * are quick_hack. - * - * current gpio frame work doesn't have - * the method to control only pull up/down/free. - * this function should be replaced by correct gpio function - */ -static void __init gpio_no_direction(u32 addr) -{ - __raw_writeb(0x00, addr); -} - /* TouchScreen */ #ifdef CONFIG_AP4EVB_QHD # define GPIO_TSC_IRQ GPIO_FN_IRQ28_123 @@ -1224,6 +1232,12 @@ static void __init ap4evb_init(void) u32 srcr4; struct clk *clk; + regulator_register_always_on(0, "fixed-1.8V", fixed1v8_power_consumers, + ARRAY_SIZE(fixed1v8_power_consumers), 1800000); + regulator_register_always_on(1, "fixed-3.3V", fixed3v3_power_consumers, + ARRAY_SIZE(fixed3v3_power_consumers), 3300000); + regulator_register_fixed(2, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + /* External clock source */ clk_set_rate(&sh7372_dv_clki_clk, 27000000); @@ -1302,8 +1316,8 @@ static void __init ap4evb_init(void) gpio_request(GPIO_PORT9, NULL); gpio_request(GPIO_PORT10, NULL); - gpio_no_direction(GPIO_PORT9CR); /* FSIAOBT needs no direction */ - gpio_no_direction(GPIO_PORT10CR); /* FSIAOLR needs no direction */ + gpio_direction_none(GPIO_PORT9CR); /* FSIAOBT needs no direction */ + gpio_direction_none(GPIO_PORT10CR); /* FSIAOLR needs no direction */ /* card detect pin for MMC slot (CN7) */ gpio_request(GPIO_PORT41, NULL); @@ -1447,14 +1461,14 @@ static void __init ap4evb_init(void) platform_add_devices(ap4evb_devices, ARRAY_SIZE(ap4evb_devices)); - sh7372_add_device_to_domain(&sh7372_a4lc, &lcdc1_device); - sh7372_add_device_to_domain(&sh7372_a4lc, &lcdc_device); - sh7372_add_device_to_domain(&sh7372_a4mp, &fsi_device); + rmobile_add_device_to_domain(&sh7372_pd_a4lc, &lcdc1_device); + rmobile_add_device_to_domain(&sh7372_pd_a4lc, &lcdc_device); + rmobile_add_device_to_domain(&sh7372_pd_a4mp, &fsi_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &sh_mmcif_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi0_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi1_device); - sh7372_add_device_to_domain(&sh7372_a4r, &ceu_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sh_mmcif_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sdhi0_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sdhi1_device); + rmobile_add_device_to_domain(&sh7372_pd_a4r, &ceu_device); hdmi_init_pm_clock(); fsi_init_pm_clock(); diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c index 9bd135531d7..cf10f92856d 100644 --- a/arch/arm/mach-shmobile/board-armadillo800eva.c +++ b/arch/arm/mach-shmobile/board-armadillo800eva.c @@ -28,6 +28,8 @@ #include <linux/platform_device.h> #include <linux/gpio.h> #include <linux/gpio_keys.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/sh_eth.h> #include <linux/videodev2.h> #include <linux/usb/renesas_usbhs.h> @@ -37,14 +39,20 @@ #include <linux/mmc/sh_mobile_sdhi.h> #include <mach/common.h> #include <mach/irqs.h> +#include <mach/r8a7740.h> +#include <media/mt9t112.h> +#include <media/sh_mobile_ceu.h> +#include <media/soc_camera.h> #include <asm/page.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/mach/time.h> #include <asm/hardware/cache-l2x0.h> -#include <mach/r8a7740.h> #include <video/sh_mobile_lcdc.h> +#include <video/sh_mobile_hdmi.h> +#include <sound/sh_fsi.h> +#include <sound/simple_card.h> /* * CON1 Camera Module @@ -108,6 +116,14 @@ */ /* + * FSI-WM8978 + * + * this command is required when playback. + * + * # amixer set "Headphone" 50 + */ + +/* * USB function * * When you use USB Function, @@ -117,14 +133,8 @@ * These are a little bit complex. * see * usbhsf_power_ctrl() - * - * CAUTION - * - * It uses autonomy mode for USB hotplug at this point - * (= usbhs_private.platform_callback.get_vbus is NULL), - * since we don't know what's happen on PM control - * on this workaround. */ +#define IRQ7 evt2irq(0x02e0) #define USBCR1 0xe605810a #define USBH 0xC6700000 #define USBH_USBCTR 0x10834 @@ -204,6 +214,20 @@ static void usbhsf_power_ctrl(struct platform_device *pdev, } } +static int usbhsf_get_vbus(struct platform_device *pdev) +{ + return gpio_get_value(GPIO_PORT209); +} + +static irqreturn_t usbhsf_interrupt(int irq, void *data) +{ + struct platform_device *pdev = data; + + renesas_usbhs_call_notify_hotplug(pdev); + + return IRQ_HANDLED; +} + static void usbhsf_hardware_exit(struct platform_device *pdev) { struct usbhsf_private *priv = usbhsf_get_priv(pdev); @@ -227,11 +251,14 @@ static void usbhsf_hardware_exit(struct platform_device *pdev) priv->host = NULL; priv->func = NULL; priv->usbh_base = NULL; + + free_irq(IRQ7, pdev); } static int usbhsf_hardware_init(struct platform_device *pdev) { struct usbhsf_private *priv = usbhsf_get_priv(pdev); + int ret; priv->phy = clk_get(&pdev->dev, "phy"); priv->usb24 = clk_get(&pdev->dev, "usb24"); @@ -251,6 +278,14 @@ static int usbhsf_hardware_init(struct platform_device *pdev) return -EIO; } + ret = request_irq(IRQ7, usbhsf_interrupt, IRQF_TRIGGER_NONE, + dev_name(&pdev->dev), pdev); + if (ret) { + dev_err(&pdev->dev, "request_irq err\n"); + return ret; + } + irq_set_irq_type(IRQ7, IRQ_TYPE_EDGE_BOTH); + /* usb24 use 1/1 of parent clock (= usb24s = 24MHz) */ clk_set_rate(priv->usb24, clk_get_rate(clk_get_parent(priv->usb24))); @@ -262,6 +297,7 @@ static struct usbhsf_private usbhsf_private = { .info = { .platform_callback = { .get_id = usbhsf_get_id, + .get_vbus = usbhsf_get_vbus, .hardware_init = usbhsf_hardware_init, .hardware_exit = usbhsf_hardware_exit, .power_ctrl = usbhsf_power_ctrl, @@ -269,6 +305,8 @@ static struct usbhsf_private usbhsf_private = { .driver_param = { .buswait_bwait = 5, .detection_delay = 5, + .d0_rx_id = SHDMA_SLAVE_USBHS_RX, + .d1_tx_id = SHDMA_SLAVE_USBHS_TX, }, } }; @@ -384,6 +422,103 @@ static struct platform_device lcdc0_device = { }, }; +/* + * LCDC1/HDMI + */ +static struct sh_mobile_hdmi_info hdmi_info = { + .flags = HDMI_OUTPUT_PUSH_PULL | + HDMI_OUTPUT_POLARITY_HI | + HDMI_32BIT_REG | + HDMI_HAS_HTOP1 | + HDMI_SND_SRC_SPDIF, +}; + +static struct resource hdmi_resources[] = { + [0] = { + .name = "HDMI", + .start = 0xe6be0000, + .end = 0xe6be03ff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = evt2irq(0x1700), + .flags = IORESOURCE_IRQ, + }, + [2] = { + .name = "HDMI emma3pf", + .start = 0xe6be4000, + .end = 0xe6be43ff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device hdmi_device = { + .name = "sh-mobile-hdmi", + .num_resources = ARRAY_SIZE(hdmi_resources), + .resource = hdmi_resources, + .id = -1, + .dev = { + .platform_data = &hdmi_info, + }, +}; + +static const struct fb_videomode lcdc1_mode = { + .name = "HDMI 720p", + .xres = 1280, + .yres = 720, + .pixclock = 13468, + .left_margin = 220, + .right_margin = 110, + .hsync_len = 40, + .upper_margin = 20, + .lower_margin = 5, + .vsync_len = 5, + .refresh = 60, + .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT, +}; + +static struct sh_mobile_lcdc_info hdmi_lcdc_info = { + .clock_source = LCDC_CLK_PERIPHERAL, /* HDMI clock */ + .ch[0] = { + .chan = LCDC_CHAN_MAINLCD, + .fourcc = V4L2_PIX_FMT_RGB565, + .interface_type = RGB24, + .clock_divider = 1, + .flags = LCDC_FLAGS_DWPOL, + .lcd_modes = &lcdc1_mode, + .num_modes = 1, + .tx_dev = &hdmi_device, + .panel_cfg = { + .width = 1280, + .height = 720, + }, + }, +}; + +static struct resource hdmi_lcdc_resources[] = { + [0] = { + .name = "LCDC1", + .start = 0xfe944000, + .end = 0xfe948000 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = intcs_evt2irq(0x1780), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device hdmi_lcdc_device = { + .name = "sh_mobile_lcdc_fb", + .num_resources = ARRAY_SIZE(hdmi_lcdc_resources), + .resource = hdmi_lcdc_resources, + .id = 1, + .dev = { + .platform_data = &hdmi_lcdc_info, + .coherent_dma_mask = ~0, + }, +}; + /* GPIO KEY */ #define GPIO_KEY(c, g, d) { .code = c, .gpio = g, .desc = d, .active_low = 1 } @@ -407,6 +542,17 @@ static struct platform_device gpio_keys_device = { }, }; +/* Fixed 3.3V regulator to be used by SDHI0, SDHI1, MMCIF */ +static struct regulator_consumer_supply fixed3v3_power_consumers[] = +{ + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.1"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.1"), + REGULATOR_SUPPLY("vmmc", "sh_mmcif"), + REGULATOR_SUPPLY("vqmmc", "sh_mmcif"), +}; + /* SDHI0 */ /* * FIXME @@ -418,6 +564,8 @@ static struct platform_device gpio_keys_device = { */ #define IRQ31 evt2irq(0x33E0) static struct sh_mobile_sdhi_info sdhi0_info = { + .dma_slave_tx = SHDMA_SLAVE_SDHI0_TX, + .dma_slave_rx = SHDMA_SLAVE_SDHI0_RX, .tmio_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |\ MMC_CAP_NEEDS_POLL, .tmio_ocr_mask = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34, @@ -458,6 +606,8 @@ static struct platform_device sdhi0_device = { /* SDHI1 */ static struct sh_mobile_sdhi_info sdhi1_info = { + .dma_slave_tx = SHDMA_SLAVE_SDHI1_TX, + .dma_slave_rx = SHDMA_SLAVE_SDHI1_RX, .tmio_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, .tmio_ocr_mask = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34, .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT, @@ -532,12 +682,209 @@ static struct platform_device sh_mmcif_device = { .resource = sh_mmcif_resources, }; +/* Camera */ +static int mt9t111_power(struct device *dev, int mode) +{ + struct clk *mclk = clk_get(NULL, "video1"); + + if (IS_ERR(mclk)) { + dev_err(dev, "can't get video1 clock\n"); + return -EINVAL; + } + + if (mode) { + /* video1 (= CON1 camera) expect 24MHz */ + clk_set_rate(mclk, clk_round_rate(mclk, 24000000)); + clk_enable(mclk); + gpio_direction_output(GPIO_PORT158, 1); + } else { + gpio_direction_output(GPIO_PORT158, 0); + clk_disable(mclk); + } + + clk_put(mclk); + + return 0; +} + +static struct i2c_board_info i2c_camera_mt9t111 = { + I2C_BOARD_INFO("mt9t112", 0x3d), +}; + +static struct mt9t112_camera_info mt9t111_info = { + .divider = { 16, 0, 0, 7, 0, 10, 14, 7, 7 }, +}; + +static struct soc_camera_link mt9t111_link = { + .i2c_adapter_id = 0, + .bus_id = 0, + .board_info = &i2c_camera_mt9t111, + .power = mt9t111_power, + .priv = &mt9t111_info, +}; + +static struct platform_device camera_device = { + .name = "soc-camera-pdrv", + .id = 0, + .dev = { + .platform_data = &mt9t111_link, + }, +}; + +/* CEU0 */ +static struct sh_mobile_ceu_info sh_mobile_ceu0_info = { + .flags = SH_CEU_FLAG_LOWER_8BIT, +}; + +static struct resource ceu0_resources[] = { + [0] = { + .name = "CEU", + .start = 0xfe910000, + .end = 0xfe91009f, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = intcs_evt2irq(0x0500), + .flags = IORESOURCE_IRQ, + }, + [2] = { + /* place holder for contiguous memory */ + }, +}; + +static struct platform_device ceu0_device = { + .name = "sh_mobile_ceu", + .id = 0, + .num_resources = ARRAY_SIZE(ceu0_resources), + .resource = ceu0_resources, + .dev = { + .platform_data = &sh_mobile_ceu0_info, + .coherent_dma_mask = 0xffffffff, + }, +}; + +/* FSI */ +static int fsi_hdmi_set_rate(struct device *dev, int rate, int enable) +{ + struct clk *fsib; + int ret; + + /* it support 48KHz only */ + if (48000 != rate) + return -EINVAL; + + fsib = clk_get(dev, "ickb"); + if (IS_ERR(fsib)) + return -EINVAL; + + if (enable) { + ret = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64; + clk_enable(fsib); + } else { + ret = 0; + clk_disable(fsib); + } + + clk_put(fsib); + + return ret; +} + +static struct sh_fsi_platform_info fsi_info = { + /* FSI-WM8978 */ + .port_a = { + .tx_id = SHDMA_SLAVE_FSIA_TX, + }, + /* FSI-HDMI */ + .port_b = { + .flags = SH_FSI_FMT_SPDIF | + SH_FSI_ENABLE_STREAM_MODE, + .set_rate = fsi_hdmi_set_rate, + .tx_id = SHDMA_SLAVE_FSIB_TX, + } +}; + +static struct resource fsi_resources[] = { + [0] = { + .name = "FSI", + .start = 0xfe1f0000, + .end = 0xfe1f8400 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = evt2irq(0x1840), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device fsi_device = { + .name = "sh_fsi2", + .id = -1, + .num_resources = ARRAY_SIZE(fsi_resources), + .resource = fsi_resources, + .dev = { + .platform_data = &fsi_info, + }, +}; + +/* FSI-WM8978 */ +static struct asoc_simple_dai_init_info fsi_wm8978_init_info = { + .fmt = SND_SOC_DAIFMT_I2S, + .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF, + .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS, + .sysclk = 12288000, +}; + +static struct asoc_simple_card_info fsi_wm8978_info = { + .name = "wm8978", + .card = "FSI2A-WM8978", + .cpu_dai = "fsia-dai", + .codec = "wm8978.0-001a", + .platform = "sh_fsi2", + .codec_dai = "wm8978-hifi", + .init = &fsi_wm8978_init_info, +}; + +static struct platform_device fsi_wm8978_device = { + .name = "asoc-simple-card", + .id = 0, + .dev = { + .platform_data = &fsi_wm8978_info, + }, +}; + +/* FSI-HDMI */ +static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = { + .cpu_daifmt = SND_SOC_DAIFMT_CBM_CFM, +}; + +static struct asoc_simple_card_info fsi2_hdmi_info = { + .name = "HDMI", + .card = "FSI2B-HDMI", + .cpu_dai = "fsib-dai", + .codec = "sh-mobile-hdmi", + .platform = "sh_fsi2", + .codec_dai = "sh_mobile_hdmi-hifi", + .init = &fsi2_hdmi_init_info, +}; + +static struct platform_device fsi_hdmi_device = { + .name = "asoc-simple-card", + .id = 1, + .dev = { + .platform_data = &fsi2_hdmi_info, + }, +}; + /* I2C */ static struct i2c_board_info i2c0_devices[] = { { I2C_BOARD_INFO("st1232-ts", 0x55), .irq = evt2irq(0x0340), }, + { + I2C_BOARD_INFO("wm8978", 0x1a), + }, }; /* @@ -549,6 +896,13 @@ static struct platform_device *eva_devices[] __initdata = { &sh_eth_device, &sdhi0_device, &sh_mmcif_device, + &hdmi_device, + &hdmi_lcdc_device, + &camera_device, + &ceu0_device, + &fsi_device, + &fsi_hdmi_device, + &fsi_wm8978_device, }; static void __init eva_clock_init(void) @@ -556,10 +910,14 @@ static void __init eva_clock_init(void) struct clk *system = clk_get(NULL, "system_clk"); struct clk *xtal1 = clk_get(NULL, "extal1"); struct clk *usb24s = clk_get(NULL, "usb24s"); + struct clk *fsibck = clk_get(NULL, "fsibck"); + struct clk *fsib = clk_get(&fsi_device.dev, "ickb"); if (IS_ERR(system) || IS_ERR(xtal1) || - IS_ERR(usb24s)) { + IS_ERR(usb24s) || + IS_ERR(fsibck) || + IS_ERR(fsib)) { pr_err("armadillo800eva board clock init failed\n"); goto clock_error; } @@ -570,6 +928,11 @@ static void __init eva_clock_init(void) /* usb24s use extal1 (= system) clock (= 24MHz) */ clk_set_parent(usb24s, system); + /* FSIBCK is 12.288MHz, and it is parent of FSI-B */ + clk_set_parent(fsib, fsibck); + clk_set_rate(fsibck, 12288000); + clk_set_rate(fsib, 12288000); + clock_error: if (!IS_ERR(system)) clk_put(system); @@ -577,16 +940,26 @@ clock_error: clk_put(xtal1); if (!IS_ERR(usb24s)) clk_put(usb24s); + if (!IS_ERR(fsibck)) + clk_put(fsibck); + if (!IS_ERR(fsib)) + clk_put(fsib); } /* * board init */ +#define GPIO_PORT7CR 0xe6050007 +#define GPIO_PORT8CR 0xe6050008 static void __init eva_init(void) { - eva_clock_init(); + struct platform_device *usb = NULL; + + regulator_register_always_on(0, "fixed-3.3V", fixed3v3_power_consumers, + ARRAY_SIZE(fixed3v3_power_consumers), 3300000); r8a7740_pinmux_init(); + r8a7740_meram_workaround(); /* SCIFA1 */ gpio_request(GPIO_FN_SCIFA1_RXD, NULL); @@ -667,8 +1040,19 @@ static void __init eva_init(void) /* USB Host */ } else { /* USB Func */ - gpio_request(GPIO_FN_VBUS, NULL); + /* + * A1 chip has 2 IRQ7 pin and it was controled by MSEL register. + * OTOH, usbhs interrupt needs its value (HI/LOW) to decide + * USB connection/disconnection (usbhsf_get_vbus()). + * This means we needs to select GPIO_FN_IRQ7_PORT209 first, + * and select GPIO_PORT209 here + */ + gpio_request(GPIO_FN_IRQ7_PORT209, NULL); + gpio_request(GPIO_PORT209, NULL); + gpio_direction_input(GPIO_PORT209); + platform_device_register(&usbhsf_device); + usb = &usbhsf_device; } /* SDHI0 */ @@ -706,6 +1090,48 @@ static void __init eva_init(void) gpio_request(GPIO_FN_MMC1_D6_PORT143, NULL); gpio_request(GPIO_FN_MMC1_D7_PORT142, NULL); + /* CEU0 */ + gpio_request(GPIO_FN_VIO0_D7, NULL); + gpio_request(GPIO_FN_VIO0_D6, NULL); + gpio_request(GPIO_FN_VIO0_D5, NULL); + gpio_request(GPIO_FN_VIO0_D4, NULL); + gpio_request(GPIO_FN_VIO0_D3, NULL); + gpio_request(GPIO_FN_VIO0_D2, NULL); + gpio_request(GPIO_FN_VIO0_D1, NULL); + gpio_request(GPIO_FN_VIO0_D0, NULL); + gpio_request(GPIO_FN_VIO0_CLK, NULL); + gpio_request(GPIO_FN_VIO0_HD, NULL); + gpio_request(GPIO_FN_VIO0_VD, NULL); + gpio_request(GPIO_FN_VIO0_FIELD, NULL); + gpio_request(GPIO_FN_VIO_CKO, NULL); + + /* CON1/CON15 Camera */ + gpio_request(GPIO_PORT173, NULL); /* STANDBY */ + gpio_request(GPIO_PORT172, NULL); /* RST */ + gpio_request(GPIO_PORT158, NULL); /* CAM_PON */ + gpio_direction_output(GPIO_PORT173, 0); + gpio_direction_output(GPIO_PORT172, 1); + gpio_direction_output(GPIO_PORT158, 0); /* see mt9t111_power() */ + + /* FSI-WM8978 */ + gpio_request(GPIO_FN_FSIAIBT, NULL); + gpio_request(GPIO_FN_FSIAILR, NULL); + gpio_request(GPIO_FN_FSIAOMC, NULL); + gpio_request(GPIO_FN_FSIAOSLD, NULL); + gpio_request(GPIO_FN_FSIAISLD_PORT5, NULL); + + gpio_request(GPIO_PORT7, NULL); + gpio_request(GPIO_PORT8, NULL); + gpio_direction_none(GPIO_PORT7CR); /* FSIAOBT needs no direction */ + gpio_direction_none(GPIO_PORT8CR); /* FSIAOLR needs no direction */ + + /* FSI-HDMI */ + gpio_request(GPIO_FN_FSIBCK, NULL); + + /* HDMI */ + gpio_request(GPIO_FN_HDMI_HPD, NULL); + gpio_request(GPIO_FN_HDMI_CEC, NULL); + /* * CAUTION * @@ -752,6 +1178,13 @@ static void __init eva_init(void) platform_add_devices(eva_devices, ARRAY_SIZE(eva_devices)); + + eva_clock_init(); + + rmobile_add_device_to_domain(&r8a7740_pd_a4lc, &lcdc0_device); + rmobile_add_device_to_domain(&r8a7740_pd_a4lc, &hdmi_lcdc_device); + if (usb) + rmobile_add_device_to_domain(&r8a7740_pd_a3sp, usb); } static void __init eva_earlytimer_init(void) diff --git a/arch/arm/mach-shmobile/board-bonito.c b/arch/arm/mach-shmobile/board-bonito.c index e9b32cfbf74..4129008eae2 100644 --- a/arch/arm/mach-shmobile/board-bonito.c +++ b/arch/arm/mach-shmobile/board-bonito.c @@ -26,6 +26,8 @@ #include <linux/irq.h> #include <linux/platform_device.h> #include <linux/gpio.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/smsc911x.h> #include <linux/videodev2.h> #include <mach/common.h> @@ -75,6 +77,12 @@ * S38.2 = OFF */ +/* Dummy supplies, where voltage doesn't matter */ +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vddvario", "smsc911x"), + REGULATOR_SUPPLY("vdd33a", "smsc911x"), +}; + /* * FPGA */ @@ -360,6 +368,8 @@ static void __init bonito_init(void) { u16 val; + regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + r8a7740_pinmux_init(); bonito_fpga_init(); diff --git a/arch/arm/mach-shmobile/board-g4evm.c b/arch/arm/mach-shmobile/board-g4evm.c index f1257321999..fa5dfc5c8ed 100644 --- a/arch/arm/mach-shmobile/board-g4evm.c +++ b/arch/arm/mach-shmobile/board-g4evm.c @@ -26,6 +26,8 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/mtd/physmap.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/usb/r8a66597.h> #include <linux/io.h> #include <linux/input.h> @@ -196,6 +198,15 @@ static struct platform_device keysc_device = { }, }; +/* Fixed 3.3V regulator to be used by SDHI0 and SDHI1 */ +static struct regulator_consumer_supply fixed3v3_power_consumers[] = +{ + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.1"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.1"), +}; + /* SDHI */ static struct sh_mobile_sdhi_info sdhi0_info = { .tmio_caps = MMC_CAP_SDIO_IRQ, @@ -271,26 +282,11 @@ static struct platform_device *g4evm_devices[] __initdata = { #define GPIO_SDHID1_D3 0xe6052106 #define GPIO_SDHICMD1 0xe6052107 -/* - * FIXME !! - * - * gpio_pull_up is quick_hack. - * - * current gpio frame work doesn't have - * the method to control only pull up/down/free. - * this function should be replaced by correct gpio function - */ -static void __init gpio_pull_up(u32 addr) -{ - u8 data = __raw_readb(addr); - - data &= 0x0F; - data |= 0xC0; - __raw_writeb(data, addr); -} - static void __init g4evm_init(void) { + regulator_register_always_on(0, "fixed-3.3V", fixed3v3_power_consumers, + ARRAY_SIZE(fixed3v3_power_consumers), 3300000); + sh7377_pinmux_init(); /* Lit DS14 LED */ @@ -351,11 +347,11 @@ static void __init g4evm_init(void) gpio_request(GPIO_FN_SDHID0_3, NULL); gpio_request(GPIO_FN_SDHICMD0, NULL); gpio_request(GPIO_FN_SDHIWP0, NULL); - gpio_pull_up(GPIO_SDHID0_D0); - gpio_pull_up(GPIO_SDHID0_D1); - gpio_pull_up(GPIO_SDHID0_D2); - gpio_pull_up(GPIO_SDHID0_D3); - gpio_pull_up(GPIO_SDHICMD0); + gpio_request_pullup(GPIO_SDHID0_D0); + gpio_request_pullup(GPIO_SDHID0_D1); + gpio_request_pullup(GPIO_SDHID0_D2); + gpio_request_pullup(GPIO_SDHID0_D3); + gpio_request_pullup(GPIO_SDHICMD0); /* SDHI1 */ gpio_request(GPIO_FN_SDHICLK1, NULL); @@ -364,11 +360,11 @@ static void __init g4evm_init(void) gpio_request(GPIO_FN_SDHID1_2, NULL); gpio_request(GPIO_FN_SDHID1_3, NULL); gpio_request(GPIO_FN_SDHICMD1, NULL); - gpio_pull_up(GPIO_SDHID1_D0); - gpio_pull_up(GPIO_SDHID1_D1); - gpio_pull_up(GPIO_SDHID1_D2); - gpio_pull_up(GPIO_SDHID1_D3); - gpio_pull_up(GPIO_SDHICMD1); + gpio_request_pullup(GPIO_SDHID1_D0); + gpio_request_pullup(GPIO_SDHID1_D1); + gpio_request_pullup(GPIO_SDHID1_D2); + gpio_request_pullup(GPIO_SDHID1_D3); + gpio_request_pullup(GPIO_SDHICMD1); sh7377_add_standard_devices(); diff --git a/arch/arm/mach-shmobile/board-kota2.c b/arch/arm/mach-shmobile/board-kota2.c index f60f1b281cc..21dbe54304d 100644 --- a/arch/arm/mach-shmobile/board-kota2.c +++ b/arch/arm/mach-shmobile/board-kota2.c @@ -27,6 +27,8 @@ #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/io.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/smsc911x.h> #include <linux/gpio.h> #include <linux/input.h> @@ -49,6 +51,12 @@ #include <asm/hardware/cache-l2x0.h> #include <asm/traps.h> +/* Dummy supplies, where voltage doesn't matter */ +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vddvario", "smsc911x"), + REGULATOR_SUPPLY("vdd33a", "smsc911x"), +}; + /* SMSC 9220 */ static struct resource smsc9220_resources[] = { [0] = { @@ -288,6 +296,13 @@ static struct platform_device leds_tpu30_device = { .resource = tpu30_resources, }; +/* Fixed 1.8V regulator to be used by MMCIF */ +static struct regulator_consumer_supply fixed1v8_power_consumers[] = +{ + REGULATOR_SUPPLY("vmmc", "sh_mmcif.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mmcif.0"), +}; + /* MMCIF */ static struct resource mmcif_resources[] = { [0] = { @@ -321,6 +336,15 @@ static struct platform_device mmcif_device = { .resource = mmcif_resources, }; +/* Fixed 3.3V regulator to be used by SDHI0 and SDHI1 */ +static struct regulator_consumer_supply fixed3v3_power_consumers[] = +{ + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.1"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.1"), +}; + /* SDHI0 */ static struct sh_mobile_sdhi_info sdhi0_info = { .tmio_caps = MMC_CAP_SD_HIGHSPEED, @@ -411,6 +435,12 @@ static struct platform_device *kota2_devices[] __initdata = { static void __init kota2_init(void) { + regulator_register_always_on(0, "fixed-1.8V", fixed1v8_power_consumers, + ARRAY_SIZE(fixed1v8_power_consumers), 1800000); + regulator_register_always_on(1, "fixed-3.3V", fixed3v3_power_consumers, + ARRAY_SIZE(fixed3v3_power_consumers), 3300000); + regulator_register_fixed(2, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + sh73a0_pinmux_init(); /* SCIFA2 (UART2) */ diff --git a/arch/arm/mach-shmobile/board-kzm9d.c b/arch/arm/mach-shmobile/board-kzm9d.c index 6a33cf39342..2c986eaae7b 100644 --- a/arch/arm/mach-shmobile/board-kzm9d.c +++ b/arch/arm/mach-shmobile/board-kzm9d.c @@ -21,6 +21,8 @@ #include <linux/kernel.h> #include <linux/interrupt.h> #include <linux/platform_device.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/smsc911x.h> #include <mach/common.h> #include <mach/emev2.h> @@ -28,6 +30,12 @@ #include <asm/mach/arch.h> #include <asm/hardware/gic.h> +/* Dummy supplies, where voltage doesn't matter */ +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vddvario", "smsc911x"), + REGULATOR_SUPPLY("vdd33a", "smsc911x"), +}; + /* Ether */ static struct resource smsc911x_resources[] = { [0] = { @@ -63,6 +71,8 @@ static struct platform_device *kzm9d_devices[] __initdata = { void __init kzm9d_add_standard_devices(void) { + regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + emev2_add_standard_devices(); platform_add_devices(kzm9d_devices, ARRAY_SIZE(kzm9d_devices)); diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c index c0ae815e7be..53b7ea92c32 100644 --- a/arch/arm/mach-shmobile/board-kzm9g.c +++ b/arch/arm/mach-shmobile/board-kzm9g.c @@ -30,9 +30,14 @@ #include <linux/mmc/sh_mobile_sdhi.h> #include <linux/mfd/tmio.h> #include <linux/platform_device.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/smsc911x.h> #include <linux/usb/r8a66597.h> +#include <linux/usb/renesas_usbhs.h> #include <linux/videodev2.h> +#include <sound/sh_fsi.h> +#include <sound/simple_card.h> #include <mach/irqs.h> #include <mach/sh73a0.h> #include <mach/common.h> @@ -54,6 +59,20 @@ #define GPIO_PCF8575_PORT15 (GPIO_NR + 13) #define GPIO_PCF8575_PORT16 (GPIO_NR + 14) +/* Dummy supplies, where voltage doesn't matter */ +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vddvario", "smsc911x"), + REGULATOR_SUPPLY("vdd33a", "smsc911x"), +}; + +/* + * FSI-AK4648 + * + * this command is required when playback. + * + * # amixer set "LINEOUT Mixer DACL" on + */ + /* SMSC 9221 */ static struct resource smsc9221_resources[] = { [0] = { @@ -112,6 +131,151 @@ static struct platform_device usb_host_device = { .resource = usb_resources, }; +/* USB Func CN17 */ +struct usbhs_private { + unsigned int phy; + unsigned int cr2; + struct renesas_usbhs_platform_info info; +}; + +#define IRQ15 intcs_evt2irq(0x03e0) +#define USB_PHY_MODE (1 << 4) +#define USB_PHY_INT_EN ((1 << 3) | (1 << 2)) +#define USB_PHY_ON (1 << 1) +#define USB_PHY_OFF (1 << 0) +#define USB_PHY_INT_CLR (USB_PHY_ON | USB_PHY_OFF) + +#define usbhs_get_priv(pdev) \ + container_of(renesas_usbhs_get_info(pdev), struct usbhs_private, info) + +static int usbhs_get_vbus(struct platform_device *pdev) +{ + struct usbhs_private *priv = usbhs_get_priv(pdev); + + return !((1 << 7) & __raw_readw(priv->cr2)); +} + +static void usbhs_phy_reset(struct platform_device *pdev) +{ + struct usbhs_private *priv = usbhs_get_priv(pdev); + + /* init phy */ + __raw_writew(0x8a0a, priv->cr2); +} + +static int usbhs_get_id(struct platform_device *pdev) +{ + return USBHS_GADGET; +} + +static irqreturn_t usbhs_interrupt(int irq, void *data) +{ + struct platform_device *pdev = data; + struct usbhs_private *priv = usbhs_get_priv(pdev); + + renesas_usbhs_call_notify_hotplug(pdev); + + /* clear status */ + __raw_writew(__raw_readw(priv->phy) | USB_PHY_INT_CLR, priv->phy); + + return IRQ_HANDLED; +} + +static int usbhs_hardware_init(struct platform_device *pdev) +{ + struct usbhs_private *priv = usbhs_get_priv(pdev); + int ret; + + /* clear interrupt status */ + __raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->phy); + + ret = request_irq(IRQ15, usbhs_interrupt, IRQF_TRIGGER_HIGH, + dev_name(&pdev->dev), pdev); + if (ret) { + dev_err(&pdev->dev, "request_irq err\n"); + return ret; + } + + /* enable USB phy interrupt */ + __raw_writew(USB_PHY_MODE | USB_PHY_INT_EN, priv->phy); + + return 0; +} + +static void usbhs_hardware_exit(struct platform_device *pdev) +{ + struct usbhs_private *priv = usbhs_get_priv(pdev); + + /* clear interrupt status */ + __raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->phy); + + free_irq(IRQ15, pdev); +} + +static u32 usbhs_pipe_cfg[] = { + USB_ENDPOINT_XFER_CONTROL, + USB_ENDPOINT_XFER_ISOC, + USB_ENDPOINT_XFER_ISOC, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_INT, + USB_ENDPOINT_XFER_INT, + USB_ENDPOINT_XFER_INT, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, +}; + +static struct usbhs_private usbhs_private = { + .phy = 0xe60781e0, /* USBPHYINT */ + .cr2 = 0xe605810c, /* USBCR2 */ + .info = { + .platform_callback = { + .hardware_init = usbhs_hardware_init, + .hardware_exit = usbhs_hardware_exit, + .get_id = usbhs_get_id, + .phy_reset = usbhs_phy_reset, + .get_vbus = usbhs_get_vbus, + }, + .driver_param = { + .buswait_bwait = 4, + .has_otg = 1, + .pipe_type = usbhs_pipe_cfg, + .pipe_size = ARRAY_SIZE(usbhs_pipe_cfg), + }, + }, +}; + +static struct resource usbhs_resources[] = { + [0] = { + .start = 0xE6890000, + .end = 0xE68900e6 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = gic_spi(62), + .end = gic_spi(62), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device usbhs_device = { + .name = "renesas_usbhs", + .id = -1, + .dev = { + .dma_mask = NULL, + .coherent_dma_mask = 0xffffffff, + .platform_data = &usbhs_private.info, + }, + .num_resources = ARRAY_SIZE(usbhs_resources), + .resource = usbhs_resources, +}; + /* LCDC */ static struct fb_videomode kzm_lcdc_mode = { .name = "WVGA Panel", @@ -166,6 +330,13 @@ static struct platform_device lcdc_device = { }, }; +/* Fixed 1.8V regulator to be used by MMCIF */ +static struct regulator_consumer_supply fixed1v8_power_consumers[] = +{ + REGULATOR_SUPPLY("vmmc", "sh_mmcif.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mmcif.0"), +}; + /* MMCIF */ static struct resource sh_mmcif_resources[] = { [0] = { @@ -187,6 +358,8 @@ static struct resource sh_mmcif_resources[] = { static struct sh_mmcif_plat_data sh_mmcif_platdata = { .ocr = MMC_VDD_165_195, .caps = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE, + .slave_id_tx = SHDMA_SLAVE_MMCIF_TX, + .slave_id_rx = SHDMA_SLAVE_MMCIF_RX, }; static struct platform_device mmc_device = { @@ -200,6 +373,15 @@ static struct platform_device mmc_device = { .resource = sh_mmcif_resources, }; +/* Fixed 2.8V regulators to be used by SDHI0 and SDHI2 */ +static struct regulator_consumer_supply fixed2v8_power_consumers[] = +{ + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.2"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.2"), +}; + /* SDHI */ static struct sh_mobile_sdhi_info sdhi0_info = { .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT, @@ -240,6 +422,50 @@ static struct platform_device sdhi0_device = { }, }; +/* Micro SD */ +static struct sh_mobile_sdhi_info sdhi2_info = { + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | + TMIO_MMC_USE_GPIO_CD | + TMIO_MMC_WRPROTECT_DISABLE, + .tmio_caps = MMC_CAP_SD_HIGHSPEED, + .tmio_ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29, + .cd_gpio = GPIO_PORT13, +}; + +static struct resource sdhi2_resources[] = { + [0] = { + .name = "SDHI2", + .start = 0xee140000, + .end = 0xee1400ff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = SH_MOBILE_SDHI_IRQ_CARD_DETECT, + .start = gic_spi(103), + .flags = IORESOURCE_IRQ, + }, + [2] = { + .name = SH_MOBILE_SDHI_IRQ_SDCARD, + .start = gic_spi(104), + .flags = IORESOURCE_IRQ, + }, + [3] = { + .name = SH_MOBILE_SDHI_IRQ_SDIO, + .start = gic_spi(105), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device sdhi2_device = { + .name = "sh_mobile_sdhi", + .id = 2, + .num_resources = ARRAY_SIZE(sdhi2_resources), + .resource = sdhi2_resources, + .dev = { + .platform_data = &sdhi2_info, + }, +}; + /* KEY */ #define GPIO_KEY(c, g, d) { .code = c, .gpio = g, .desc = d, .active_low = 1 } @@ -267,11 +493,74 @@ static struct platform_device gpio_keys_device = { }, }; +/* FSI-AK4648 */ +static struct sh_fsi_platform_info fsi_info = { + .port_a = { + .tx_id = SHDMA_SLAVE_FSI2A_TX, + }, +}; + +static struct resource fsi_resources[] = { + [0] = { + .name = "FSI", + .start = 0xEC230000, + .end = 0xEC230400 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = gic_spi(146), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device fsi_device = { + .name = "sh_fsi2", + .id = -1, + .num_resources = ARRAY_SIZE(fsi_resources), + .resource = fsi_resources, + .dev = { + .platform_data = &fsi_info, + }, +}; + +static struct asoc_simple_dai_init_info fsi2_ak4648_init_info = { + .fmt = SND_SOC_DAIFMT_LEFT_J, + .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM, + .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS, + .sysclk = 11289600, +}; + +static struct asoc_simple_card_info fsi2_ak4648_info = { + .name = "AK4648", + .card = "FSI2A-AK4648", + .cpu_dai = "fsia-dai", + .codec = "ak4642-codec.0-0012", + .platform = "sh_fsi2", + .codec_dai = "ak4642-hifi", + .init = &fsi2_ak4648_init_info, +}; + +static struct platform_device fsi_ak4648_device = { + .name = "asoc-simple-card", + .dev = { + .platform_data = &fsi2_ak4648_info, + }, +}; + /* I2C */ static struct pcf857x_platform_data pcf8575_pdata = { .gpio_base = GPIO_PCF8575_BASE, }; +static struct i2c_board_info i2c0_devices[] = { + { + I2C_BOARD_INFO("ak4648", 0x12), + }, + { + I2C_BOARD_INFO("r2025sd", 0x32), + } +}; + static struct i2c_board_info i2c1_devices[] = { { I2C_BOARD_INFO("st1232-ts", 0x55), @@ -289,10 +578,14 @@ static struct i2c_board_info i2c3_devices[] = { static struct platform_device *kzm_devices[] __initdata = { &smsc_device, &usb_host_device, + &usbhs_device, &lcdc_device, &mmc_device, &sdhi0_device, + &sdhi2_device, &gpio_keys_device, + &fsi_device, + &fsi_ak4648_device, }; /* @@ -350,6 +643,12 @@ device_initcall(as3711_enable_lcdc_backlight); static void __init kzm_init(void) { + regulator_register_always_on(0, "fixed-1.8V", fixed1v8_power_consumers, + ARRAY_SIZE(fixed1v8_power_consumers), 1800000); + regulator_register_always_on(1, "fixed-2.8V", fixed2v8_power_consumers, + ARRAY_SIZE(fixed2v8_power_consumers), 2800000); + regulator_register_fixed(2, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + sh73a0_pinmux_init(); /* enable SCIFA4 */ @@ -427,15 +726,36 @@ static void __init kzm_init(void) gpio_request(GPIO_PORT15, NULL); gpio_direction_output(GPIO_PORT15, 1); /* power */ + /* enable Micro SD */ + gpio_request(GPIO_FN_SDHID2_0, NULL); + gpio_request(GPIO_FN_SDHID2_1, NULL); + gpio_request(GPIO_FN_SDHID2_2, NULL); + gpio_request(GPIO_FN_SDHID2_3, NULL); + gpio_request(GPIO_FN_SDHICMD2, NULL); + gpio_request(GPIO_FN_SDHICLK2, NULL); + gpio_request(GPIO_PORT14, NULL); + gpio_direction_output(GPIO_PORT14, 1); /* power */ + /* I2C 3 */ gpio_request(GPIO_FN_PORT27_I2C_SCL3, NULL); gpio_request(GPIO_FN_PORT28_I2C_SDA3, NULL); + /* enable FSI2 port A (ak4648) */ + gpio_request(GPIO_FN_FSIACK, NULL); + gpio_request(GPIO_FN_FSIAILR, NULL); + gpio_request(GPIO_FN_FSIAIBT, NULL); + gpio_request(GPIO_FN_FSIAISLD, NULL); + gpio_request(GPIO_FN_FSIAOSLD, NULL); + + /* enable USB */ + gpio_request(GPIO_FN_VBUS_0, NULL); + #ifdef CONFIG_CACHE_L2X0 /* Early BRESP enable, Shared attribute override enable, 64K*8way */ l2x0_init(IOMEM(0xf0100000), 0x40460000, 0x82000fff); #endif + i2c_register_board_info(0, i2c0_devices, ARRAY_SIZE(i2c0_devices)); i2c_register_board_info(1, i2c1_devices, ARRAY_SIZE(i2c1_devices)); i2c_register_board_info(3, i2c3_devices, ARRAY_SIZE(i2c3_devices)); diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 150122a4463..7ea2b31e319 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -41,6 +41,8 @@ #include <linux/mtd/physmap.h> #include <linux/mtd/sh_flctl.h> #include <linux/pm_clock.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/smsc911x.h> #include <linux/sh_intc.h> #include <linux/tca6416_keypad.h> @@ -203,31 +205,32 @@ * amixer set "HPOUTR Mixer DACH" on */ -/* - * FIXME !! - * - * gpio_no_direction - * gpio_pull_down - * are quick_hack. - * - * current gpio frame work doesn't have - * the method to control only pull up/down/free. - * this function should be replaced by correct gpio function - */ -static void __init gpio_no_direction(u32 addr) +/* Fixed 3.3V and 1.8V regulators to be used by multiple devices */ +static struct regulator_consumer_supply fixed1v8_power_consumers[] = { - __raw_writeb(0x00, addr); -} + /* + * J22 on mackerel switches mmcif.0 and sdhi.1 between 1.8V and 3.3V + * Since we cannot support both voltages, we support the default 1.8V + */ + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.1"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.1"), + REGULATOR_SUPPLY("vmmc", "sh_mmcif.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mmcif.0"), +}; -static void __init gpio_pull_down(u32 addr) +static struct regulator_consumer_supply fixed3v3_power_consumers[] = { - u8 data = __raw_readb(addr); - - data &= 0x0F; - data |= 0xA0; + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.2"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.2"), +}; - __raw_writeb(data, addr); -} +/* Dummy supplies, where voltage doesn't matter */ +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vddvario", "smsc911x"), + REGULATOR_SUPPLY("vdd33a", "smsc911x"), +}; /* MTD */ static struct mtd_partition nor_flash_partitions[] = { @@ -1409,6 +1412,12 @@ static void __init mackerel_init(void) u32 srcr4; struct clk *clk; + regulator_register_always_on(0, "fixed-1.8V", fixed1v8_power_consumers, + ARRAY_SIZE(fixed1v8_power_consumers), 1800000); + regulator_register_always_on(1, "fixed-3.3V", fixed3v3_power_consumers, + ARRAY_SIZE(fixed3v3_power_consumers), 3300000); + regulator_register_fixed(2, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + /* External clock source */ clk_set_rate(&sh7372_dv_clki_clk, 27000000); @@ -1458,11 +1467,11 @@ static void __init mackerel_init(void) /* USBHS0 */ gpio_request(GPIO_FN_VBUS0_0, NULL); - gpio_pull_down(GPIO_PORT168CR); /* VBUS0_0 pull down */ + gpio_request_pulldown(GPIO_PORT168CR); /* VBUS0_0 pull down */ /* USBHS1 */ gpio_request(GPIO_FN_VBUS0_1, NULL); - gpio_pull_down(GPIO_PORT167CR); /* VBUS0_1 pull down */ + gpio_request_pulldown(GPIO_PORT167CR); /* VBUS0_1 pull down */ gpio_request(GPIO_FN_IDIN_1_113, NULL); /* enable FSI2 port A (ak4643) */ @@ -1475,8 +1484,8 @@ static void __init mackerel_init(void) gpio_request(GPIO_PORT9, NULL); gpio_request(GPIO_PORT10, NULL); - gpio_no_direction(GPIO_PORT9CR); /* FSIAOBT needs no direction */ - gpio_no_direction(GPIO_PORT10CR); /* FSIAOLR needs no direction */ + gpio_direction_none(GPIO_PORT9CR); /* FSIAOBT needs no direction */ + gpio_direction_none(GPIO_PORT10CR); /* FSIAOLR needs no direction */ intc_set_priority(IRQ_FSI, 3); /* irq priority FSI(3) > SMSC911X(2) */ @@ -1614,20 +1623,20 @@ static void __init mackerel_init(void) platform_add_devices(mackerel_devices, ARRAY_SIZE(mackerel_devices)); - sh7372_add_device_to_domain(&sh7372_a4lc, &lcdc_device); - sh7372_add_device_to_domain(&sh7372_a4lc, &hdmi_lcdc_device); - sh7372_add_device_to_domain(&sh7372_a4lc, &meram_device); - sh7372_add_device_to_domain(&sh7372_a4mp, &fsi_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &usbhs0_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &usbhs1_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &nand_flash_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &sh_mmcif_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi0_device); + rmobile_add_device_to_domain(&sh7372_pd_a4lc, &lcdc_device); + rmobile_add_device_to_domain(&sh7372_pd_a4lc, &hdmi_lcdc_device); + rmobile_add_device_to_domain(&sh7372_pd_a4lc, &meram_device); + rmobile_add_device_to_domain(&sh7372_pd_a4mp, &fsi_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &usbhs0_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &usbhs1_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &nand_flash_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sh_mmcif_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sdhi0_device); #if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE) - sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi1_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sdhi1_device); #endif - sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi2_device); - sh7372_add_device_to_domain(&sh7372_a4r, &ceu_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sdhi2_device); + rmobile_add_device_to_domain(&sh7372_pd_a4r, &ceu_device); hdmi_init_pm_clock(); sh7372_pm_init(); diff --git a/arch/arm/mach-shmobile/board-marzen.c b/arch/arm/mach-shmobile/board-marzen.c index 14de3787caf..3a528cf4366 100644 --- a/arch/arm/mach-shmobile/board-marzen.c +++ b/arch/arm/mach-shmobile/board-marzen.c @@ -27,6 +27,8 @@ #include <linux/io.h> #include <linux/gpio.h> #include <linux/dma-mapping.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/smsc911x.h> #include <mach/hardware.h> #include <mach/r8a7779.h> @@ -37,6 +39,12 @@ #include <asm/hardware/gic.h> #include <asm/traps.h> +/* Dummy supplies, where voltage doesn't matter */ +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vddvario", "smsc911x"), + REGULATOR_SUPPLY("vdd33a", "smsc911x"), +}; + /* SMSC LAN89218 */ static struct resource smsc911x_resources[] = { [0] = { @@ -73,6 +81,8 @@ static struct platform_device *marzen_devices[] __initdata = { static void __init marzen_init(void) { + regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + r8a7779_pinmux_init(); /* SCIF2 (CN18: DEBUG0) */ diff --git a/arch/arm/mach-shmobile/clock-r8a7740.c b/arch/arm/mach-shmobile/clock-r8a7740.c index 26eea5f2105..ad5fccc7b5e 100644 --- a/arch/arm/mach-shmobile/clock-r8a7740.c +++ b/arch/arm/mach-shmobile/clock-r8a7740.c @@ -43,7 +43,10 @@ /* CPG registers */ #define FRQCRA 0xe6150000 #define FRQCRB 0xe6150004 +#define VCLKCR1 0xE6150008 +#define VCLKCR2 0xE615000c #define FRQCRC 0xe61500e0 +#define FSIACKCR 0xe6150018 #define PLLC01CR 0xe6150028 #define SUBCKCR 0xe6150080 @@ -54,6 +57,8 @@ #define MSTPSR2 0xe6150040 #define MSTPSR3 0xe6150048 #define MSTPSR4 0xe615004c +#define FSIBCKCR 0xe6150090 +#define HDMICKCR 0xe6150094 #define SMSTPCR0 0xe6150130 #define SMSTPCR1 0xe6150134 #define SMSTPCR2 0xe6150138 @@ -271,6 +276,13 @@ static struct clk usb24_clk = { .parent = &usb24s_clk, }; +/* External FSIACK/FSIBCK clock */ +static struct clk fsiack_clk = { +}; + +static struct clk fsibck_clk = { +}; + struct clk *main_clks[] = { &extalr_clk, &extal1_clk, @@ -288,6 +300,8 @@ struct clk *main_clks[] = { &pllc1_div2_clk, &usb24s_clk, &usb24_clk, + &fsiack_clk, + &fsibck_clk, }; static void div4_kick(struct clk *clk) @@ -313,6 +327,107 @@ static struct clk_div4_table div4_table = { .kick = div4_kick, }; +/* DIV6 reparent */ +enum { + DIV6_HDMI, + DIV6_VCLK1, DIV6_VCLK2, + DIV6_FSIA, DIV6_FSIB, + DIV6_REPARENT_NR, +}; + +static struct clk *hdmi_parent[] = { + [0] = &pllc1_div2_clk, + [1] = &system_clk, + [2] = &dv_clk +}; + +static struct clk *vclk_parents[8] = { + [0] = &pllc1_div2_clk, + [2] = &dv_clk, + [3] = &usb24s_clk, + [4] = &extal1_div2_clk, + [5] = &extalr_clk, +}; + +static struct clk *fsia_parents[] = { + [0] = &pllc1_div2_clk, + [1] = &fsiack_clk, /* external clock */ +}; + +static struct clk *fsib_parents[] = { + [0] = &pllc1_div2_clk, + [1] = &fsibck_clk, /* external clock */ +}; + +static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = { + [DIV6_HDMI] = SH_CLK_DIV6_EXT(HDMICKCR, 0, + hdmi_parent, ARRAY_SIZE(hdmi_parent), 6, 2), + [DIV6_VCLK1] = SH_CLK_DIV6_EXT(VCLKCR1, 0, + vclk_parents, ARRAY_SIZE(vclk_parents), 12, 3), + [DIV6_VCLK2] = SH_CLK_DIV6_EXT(VCLKCR2, 0, + vclk_parents, ARRAY_SIZE(vclk_parents), 12, 3), + [DIV6_FSIA] = SH_CLK_DIV6_EXT(FSIACKCR, 0, + fsia_parents, ARRAY_SIZE(fsia_parents), 6, 2), + [DIV6_FSIB] = SH_CLK_DIV6_EXT(FSIBCKCR, 0, + fsib_parents, ARRAY_SIZE(fsib_parents), 6, 2), +}; + +/* HDMI1/2 clock */ +static unsigned long hdmi12_recalc(struct clk *clk) +{ + u32 val = __raw_readl(HDMICKCR); + int shift = (int)clk->priv; + + val >>= shift; + val &= 0x3; + + return clk->parent->rate / (1 << val); +}; + +static int hdmi12_set_rate(struct clk *clk, unsigned long rate) +{ + u32 val, mask; + int i, shift; + + for (i = 0; i < 3; i++) + if (rate == clk->parent->rate / (1 << i)) + goto find; + return -ENODEV; + +find: + shift = (int)clk->priv; + + val = __raw_readl(HDMICKCR); + mask = ~(0x3 << shift); + val = (val & mask) | i << shift; + __raw_writel(val, HDMICKCR); + + return 0; +}; + +static struct sh_clk_ops hdmi12_clk_ops = { + .recalc = hdmi12_recalc, + .set_rate = hdmi12_set_rate, +}; + +static struct clk hdmi1_clk = { + .ops = &hdmi12_clk_ops, + .priv = (void *)9, + .parent = &div6_reparent_clks[DIV6_HDMI], /* late install */ +}; + +static struct clk hdmi2_clk = { + .ops = &hdmi12_clk_ops, + .priv = (void *)11, + .parent = &div6_reparent_clks[DIV6_HDMI], /* late install */ +}; + +static struct clk *late_main_clks[] = { + &hdmi1_clk, + &hdmi2_clk, +}; + +/* MSTP */ enum { DIV4_I, DIV4_ZG, DIV4_B, DIV4_M1, DIV4_HP, DIV4_HPP, DIV4_USBP, DIV4_S, DIV4_ZB, DIV4_M3, DIV4_CP, @@ -343,11 +458,12 @@ static struct clk div6_clks[DIV6_NR] = { }; enum { - MSTP125, + MSTP128, MSTP127, MSTP125, MSTP116, MSTP111, MSTP100, MSTP117, MSTP230, MSTP222, + MSTP218, MSTP217, MSTP216, MSTP214, MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200, MSTP329, MSTP328, MSTP323, MSTP320, @@ -360,6 +476,8 @@ enum { }; static struct clk mstp_clks[MSTP_NR] = { + [MSTP128] = SH_CLK_MSTP32(&div4_clks[DIV4_S], SMSTPCR1, 28, 0), /* CEU21 */ + [MSTP127] = SH_CLK_MSTP32(&div4_clks[DIV4_S], SMSTPCR1, 27, 0), /* CEU20 */ [MSTP125] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR1, 25, 0), /* TMU0 */ [MSTP117] = SH_CLK_MSTP32(&div4_clks[DIV4_B], SMSTPCR1, 17, 0), /* LCDC1 */ [MSTP116] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */ @@ -368,6 +486,10 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP230] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 30, 0), /* SCIFA6 */ [MSTP222] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 22, 0), /* SCIFA7 */ + [MSTP218] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR2, 18, 0), /* DMAC1 */ + [MSTP217] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR2, 17, 0), /* DMAC2 */ + [MSTP216] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR2, 16, 0), /* DMAC3 */ + [MSTP214] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR2, 14, 0), /* USBDMAC */ [MSTP207] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 7, 0), /* SCIFA5 */ [MSTP206] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 6, 0), /* SCIFB */ [MSTP204] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 4, 0), /* SCIFA0 */ @@ -408,6 +530,12 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("pllc1_clk", &pllc1_clk), CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk), CLKDEV_CON_ID("usb24s", &usb24s_clk), + CLKDEV_CON_ID("hdmi1", &hdmi1_clk), + CLKDEV_CON_ID("hdmi2", &hdmi2_clk), + CLKDEV_CON_ID("video1", &div6_reparent_clks[DIV6_VCLK1]), + CLKDEV_CON_ID("video2", &div6_reparent_clks[DIV6_VCLK2]), + CLKDEV_CON_ID("fsiack", &fsiack_clk), + CLKDEV_CON_ID("fsibck", &fsibck_clk), /* DIV4 clocks */ CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]), @@ -430,6 +558,8 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), CLKDEV_DEV_ID("sh_mobile_lcdc_fb.1", &mstp_clks[MSTP117]), CLKDEV_DEV_ID("sh_tmu.0", &mstp_clks[MSTP125]), + CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[MSTP127]), + CLKDEV_DEV_ID("sh_mobile_ceu.1", &mstp_clks[MSTP128]), CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), @@ -438,7 +568,10 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), CLKDEV_DEV_ID("sh-sci.8", &mstp_clks[MSTP206]), CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), - + CLKDEV_DEV_ID("sh-dma-engine.3", &mstp_clks[MSTP214]), + CLKDEV_DEV_ID("sh-dma-engine.2", &mstp_clks[MSTP216]), + CLKDEV_DEV_ID("sh-dma-engine.1", &mstp_clks[MSTP217]), + CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP218]), CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP222]), CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP230]), @@ -459,6 +592,10 @@ static struct clk_lookup lookups[] = { CLKDEV_ICK_ID("phy", "renesas_usbhs", &mstp_clks[MSTP406]), CLKDEV_ICK_ID("pci", "renesas_usbhs", &div4_clks[DIV4_USBP]), CLKDEV_ICK_ID("usb24", "renesas_usbhs", &usb24_clk), + CLKDEV_ICK_ID("ick", "sh-mobile-hdmi", &div6_reparent_clks[DIV6_HDMI]), + + CLKDEV_ICK_ID("icka", "sh_fsi2", &div6_reparent_clks[DIV6_FSIA]), + CLKDEV_ICK_ID("ickb", "sh_fsi2", &div6_reparent_clks[DIV6_FSIB]), }; void __init r8a7740_clock_init(u8 md_ck) @@ -495,7 +632,14 @@ void __init r8a7740_clock_init(u8 md_ck) ret = sh_clk_div6_register(div6_clks, DIV6_NR); if (!ret) - ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); + ret = sh_clk_div6_reparent_register(div6_reparent_clks, + DIV6_REPARENT_NR); + + if (!ret) + ret = sh_clk_mstp_register(mstp_clks, MSTP_NR); + + for (k = 0; !ret && (k < ARRAY_SIZE(late_main_clks)); k++) + ret = clk_register(late_main_clks[k]); clkdev_add_table(lookups, ARRAY_SIZE(lookups)); diff --git a/arch/arm/mach-shmobile/clock-r8a7779.c b/arch/arm/mach-shmobile/clock-r8a7779.c index 7d6e9fe47b5..339c62c824d 100644 --- a/arch/arm/mach-shmobile/clock-r8a7779.c +++ b/arch/arm/mach-shmobile/clock-r8a7779.c @@ -162,7 +162,7 @@ void __init r8a7779_clock_init(void) ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table); if (!ret) - ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); + ret = sh_clk_mstp_register(mstp_clks, MSTP_NR); for (k = 0; !ret && (k < ARRAY_SIZE(late_main_clks)); k++) ret = clk_register(late_main_clks[k]); diff --git a/arch/arm/mach-shmobile/clock-sh7367.c b/arch/arm/mach-shmobile/clock-sh7367.c index 006e7b5d304..162b791b898 100644 --- a/arch/arm/mach-shmobile/clock-sh7367.c +++ b/arch/arm/mach-shmobile/clock-sh7367.c @@ -344,7 +344,7 @@ void __init sh7367_clock_init(void) ret = sh_clk_div6_register(div6_clks, DIV6_NR); if (!ret) - ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); + ret = sh_clk_mstp_register(mstp_clks, MSTP_NR); clkdev_add_table(lookups, ARRAY_SIZE(lookups)); diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 94d1f88246d..5a2894b1c96 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -704,7 +704,7 @@ void __init sh7372_clock_init(void) ret = sh_clk_div6_reparent_register(div6_reparent_clks, DIV6_REPARENT_NR); if (!ret) - ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); + ret = sh_clk_mstp_register(mstp_clks, MSTP_NR); for (k = 0; !ret && (k < ARRAY_SIZE(late_main_clks)); k++) ret = clk_register(late_main_clks[k]); diff --git a/arch/arm/mach-shmobile/clock-sh7377.c b/arch/arm/mach-shmobile/clock-sh7377.c index 0798a15936c..85f2a3ec2c4 100644 --- a/arch/arm/mach-shmobile/clock-sh7377.c +++ b/arch/arm/mach-shmobile/clock-sh7377.c @@ -355,7 +355,7 @@ void __init sh7377_clock_init(void) ret = sh_clk_div6_register(div6_clks, DIV6_NR); if (!ret) - ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); + ret = sh_clk_mstp_register(mstp_clks, MSTP_NR); clkdev_add_table(lookups, ARRAY_SIZE(lookups)); diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c index 3946c4ba2aa..7f8da18a858 100644 --- a/arch/arm/mach-shmobile/clock-sh73a0.c +++ b/arch/arm/mach-shmobile/clock-sh73a0.c @@ -475,9 +475,9 @@ static struct clk *late_main_clks[] = { enum { MSTP001, MSTP129, MSTP128, MSTP127, MSTP126, MSTP125, MSTP118, MSTP116, MSTP100, - MSTP219, MSTP218, + MSTP219, MSTP218, MSTP217, MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200, - MSTP331, MSTP329, MSTP325, MSTP323, + MSTP331, MSTP329, MSTP328, MSTP325, MSTP323, MSTP322, MSTP314, MSTP313, MSTP312, MSTP311, MSTP303, MSTP302, MSTP301, MSTP300, MSTP411, MSTP410, MSTP403, @@ -498,6 +498,7 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP100] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 0, 0), /* LCDC0 */ [MSTP219] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 19, 0), /* SCIFA7 */ [MSTP218] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 18, 0), /* SY-DMAC */ + [MSTP217] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 17, 0), /* MP-DMAC */ [MSTP207] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 7, 0), /* SCIFA5 */ [MSTP206] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 6, 0), /* SCIFB */ [MSTP204] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 4, 0), /* SCIFA0 */ @@ -507,8 +508,10 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */ [MSTP331] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 31, 0), /* SCIFA6 */ [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */ + [MSTP328] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 28, 0), /*FSI*/ [MSTP325] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 25, 0), /* IrDA */ [MSTP323] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 23, 0), /* IIC1 */ + [MSTP322] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 22, 0), /* USB */ [MSTP314] = MSTP(&div6_clks[DIV6_SDHI0], SMSTPCR3, 14, 0), /* SDHI0 */ [MSTP313] = MSTP(&div6_clks[DIV6_SDHI1], SMSTPCR3, 13, 0), /* SDHI1 */ [MSTP312] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMCIF0 */ @@ -553,6 +556,7 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[MSTP100]), /* LCDC0 */ CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP219]), /* SCIFA7 */ CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP218]), /* SY-DMAC */ + CLKDEV_DEV_ID("sh-dma-engine.1", &mstp_clks[MSTP217]), /* MP-DMAC */ CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), /* SCIFA5 */ CLKDEV_DEV_ID("sh-sci.8", &mstp_clks[MSTP206]), /* SCIFB */ CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */ @@ -562,8 +566,10 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */ CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP331]), /* SCIFA6 */ CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */ + CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), /* FSI */ CLKDEV_DEV_ID("sh_irda.0", &mstp_clks[MSTP325]), /* IrDA */ CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* I2C1 */ + CLKDEV_DEV_ID("renesas_usbhs", &mstp_clks[MSTP322]), /* USB */ CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */ CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */ CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMCIF0 */ @@ -612,7 +618,7 @@ void __init sh73a0_clock_init(void) ret = sh_clk_div6_reparent_register(div6_clks, DIV6_NR); if (!ret) - ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); + ret = sh_clk_mstp_register(mstp_clks, MSTP_NR); for (k = 0; !ret && (k < ARRAY_SIZE(late_main_clks)); k++) ret = clk_register(late_main_clks[k]); diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index 01e2bc014f1..45e61dada03 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -77,6 +77,7 @@ extern void r8a7779_add_standard_devices(void); extern void r8a7779_clock_init(void); extern void r8a7779_pinmux_init(void); extern void r8a7779_pm_init(void); +extern void r8a7740_meram_workaround(void); extern unsigned int r8a7779_get_core_count(void); extern int r8a7779_platform_cpu_kill(unsigned int cpu); diff --git a/arch/arm/mach-shmobile/include/mach/dma-register.h b/arch/arm/mach-shmobile/include/mach/dma-register.h new file mode 100644 index 00000000000..97c40bd9b94 --- /dev/null +++ b/arch/arm/mach-shmobile/include/mach/dma-register.h @@ -0,0 +1,84 @@ +/* + * SH-ARM CPU-specific DMA definitions, used by both DMA drivers + * + * Copyright (C) 2012 Renesas Solutions Corp + * + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + * + * Based on arch/sh/include/cpu-sh4/cpu/dma-register.h + * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de> + * + * 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. + */ + +#ifndef DMA_REGISTER_H +#define DMA_REGISTER_H + +/* + * Direct Memory Access Controller + */ + +/* Transmit sizes and respective CHCR register values */ +enum { + XMIT_SZ_8BIT = 0, + XMIT_SZ_16BIT = 1, + XMIT_SZ_32BIT = 2, + XMIT_SZ_64BIT = 7, + XMIT_SZ_128BIT = 3, + XMIT_SZ_256BIT = 4, + XMIT_SZ_512BIT = 5, +}; + +/* log2(size / 8) - used to calculate number of transfers */ +static const unsigned int dma_ts_shift[] = { + [XMIT_SZ_8BIT] = 0, + [XMIT_SZ_16BIT] = 1, + [XMIT_SZ_32BIT] = 2, + [XMIT_SZ_64BIT] = 3, + [XMIT_SZ_128BIT] = 4, + [XMIT_SZ_256BIT] = 5, + [XMIT_SZ_512BIT] = 6, +}; + +#define TS_LOW_BIT 0x3 /* --xx */ +#define TS_HI_BIT 0xc /* xx-- */ + +#define TS_LOW_SHIFT (3) +#define TS_HI_SHIFT (20 - 2) /* 2 bits for shifted low TS */ + +#define TS_INDEX2VAL(i) \ + ((((i) & TS_LOW_BIT) << TS_LOW_SHIFT) |\ + (((i) & TS_HI_BIT) << TS_HI_SHIFT)) + +#define CHCR_TX(xmit_sz) (DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL((xmit_sz))) +#define CHCR_RX(xmit_sz) (DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL((xmit_sz))) + + +/* + * USB High-Speed DMAC + */ +/* Transmit sizes and respective CHCR register values */ +enum { + USBTS_XMIT_SZ_8BYTE = 0, + USBTS_XMIT_SZ_16BYTE = 1, + USBTS_XMIT_SZ_32BYTE = 2, +}; + +/* log2(size / 8) - used to calculate number of transfers */ +static const unsigned int dma_usbts_shift[] = { + [USBTS_XMIT_SZ_8BYTE] = 3, + [USBTS_XMIT_SZ_16BYTE] = 4, + [USBTS_XMIT_SZ_32BYTE] = 5, +}; + +#define USBTS_LOW_BIT 0x3 /* --xx */ +#define USBTS_HI_BIT 0x0 /* ---- */ + +#define USBTS_LOW_SHIFT 6 +#define USBTS_HI_SHIFT 0 + +#define USBTS_INDEX2VAL(i) (((i) & 3) << 6) + +#endif /* DMA_REGISTER_H */ diff --git a/arch/arm/mach-shmobile/include/mach/gpio.h b/arch/arm/mach-shmobile/include/mach/gpio.h index de795b42232..844507d937c 100644 --- a/arch/arm/mach-shmobile/include/mach/gpio.h +++ b/arch/arm/mach-shmobile/include/mach/gpio.h @@ -13,6 +13,7 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/sh_pfc.h> +#include <linux/io.h> #ifdef CONFIG_GPIOLIB @@ -27,4 +28,35 @@ static inline int irq_to_gpio(unsigned int irq) #endif /* CONFIG_GPIOLIB */ +/* + * FIXME !! + * + * current gpio frame work doesn't have + * the method to control only pull up/down/free. + * this function should be replaced by correct gpio function + */ +static inline void __init gpio_direction_none(u32 addr) +{ + __raw_writeb(0x00, addr); +} + +static inline void __init gpio_request_pullup(u32 addr) +{ + u8 data = __raw_readb(addr); + + data &= 0x0F; + data |= 0xC0; + __raw_writeb(data, addr); +} + +static inline void __init gpio_request_pulldown(u32 addr) +{ + u8 data = __raw_readb(addr); + + data &= 0x0F; + data |= 0xA0; + + __raw_writeb(data, addr); +} + #endif /* __ASM_ARCH_GPIO_H */ diff --git a/arch/arm/mach-shmobile/include/mach/pm-rmobile.h b/arch/arm/mach-shmobile/include/mach/pm-rmobile.h new file mode 100644 index 00000000000..5a402840fe2 --- /dev/null +++ b/arch/arm/mach-shmobile/include/mach/pm-rmobile.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2012 Renesas Solutions Corp. + * + * Kuninori Morimoto <morimoto.kuninori@renesas.com> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#ifndef PM_RMOBILE_H +#define PM_RMOBILE_H + +#include <linux/pm_domain.h> + +struct platform_device; + +struct rmobile_pm_domain { + struct generic_pm_domain genpd; + struct dev_power_governor *gov; + int (*suspend)(void); + void (*resume)(void); + unsigned int bit_shift; + bool no_debug; +}; + +static inline +struct rmobile_pm_domain *to_rmobile_pd(struct generic_pm_domain *d) +{ + return container_of(d, struct rmobile_pm_domain, genpd); +} + +#ifdef CONFIG_PM +extern void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd); +extern void rmobile_add_device_to_domain(struct rmobile_pm_domain *rmobile_pd, + struct platform_device *pdev); +extern void rmobile_pm_add_subdomain(struct rmobile_pm_domain *rmobile_pd, + struct rmobile_pm_domain *rmobile_sd); +#else +#define rmobile_init_pm_domain(pd) do { } while (0) +#define rmobile_add_device_to_domain(pd, pdev) do { } while (0) +#define rmobile_pm_add_subdomain(pd, sd) do { } while (0) +#endif /* CONFIG_PM */ + +#endif /* PM_RMOBILE_H */ diff --git a/arch/arm/mach-shmobile/include/mach/r8a7740.h b/arch/arm/mach-shmobile/include/mach/r8a7740.h index 9d447abb969..7143147780d 100644 --- a/arch/arm/mach-shmobile/include/mach/r8a7740.h +++ b/arch/arm/mach-shmobile/include/mach/r8a7740.h @@ -19,6 +19,8 @@ #ifndef __ASM_R8A7740_H__ #define __ASM_R8A7740_H__ +#include <mach/pm-rmobile.h> + /* * MD_CKx pin */ @@ -139,7 +141,7 @@ enum { GPIO_FN_DBGMD10, GPIO_FN_DBGMD11, GPIO_FN_DBGMD20, GPIO_FN_DBGMD21, - /* FSI */ + /* FSI-A */ GPIO_FN_FSIAISLD_PORT0, /* FSIAISLD Port 0/5 */ GPIO_FN_FSIAISLD_PORT5, GPIO_FN_FSIASPDIF_PORT9, /* FSIASPDIF Port 9/18 */ @@ -150,6 +152,9 @@ enum { GPIO_FN_FSIACK, GPIO_FN_FSIAILR, GPIO_FN_FSIAIBT, + /* FSI-B */ + GPIO_FN_FSIBCK, + /* FMSI */ GPIO_FN_FMSISLD_PORT1, /* FMSISLD Port 1/6 */ GPIO_FN_FMSISLD_PORT6, @@ -565,6 +570,10 @@ enum { GPIO_FN_RESETP_PULLUP, GPIO_FN_RESETP_PLAIN, + /* HDMI */ + GPIO_FN_HDMI_HPD, + GPIO_FN_HDMI_CEC, + /* SDENC */ GPIO_FN_SDENC_CPG, GPIO_FN_SDENC_DV_CLKI, @@ -581,4 +590,26 @@ enum { GPIO_FN_TRACEAUD_FROM_MEMC, }; +/* DMA slave IDs */ +enum { + SHDMA_SLAVE_INVALID, + SHDMA_SLAVE_SDHI0_RX, + SHDMA_SLAVE_SDHI0_TX, + SHDMA_SLAVE_SDHI1_RX, + SHDMA_SLAVE_SDHI1_TX, + SHDMA_SLAVE_SDHI2_RX, + SHDMA_SLAVE_SDHI2_TX, + SHDMA_SLAVE_FSIA_RX, + SHDMA_SLAVE_FSIA_TX, + SHDMA_SLAVE_FSIB_TX, + SHDMA_SLAVE_USBHS_TX, + SHDMA_SLAVE_USBHS_RX, +}; + +#ifdef CONFIG_PM +extern struct rmobile_pm_domain r8a7740_pd_a4s; +extern struct rmobile_pm_domain r8a7740_pd_a3sp; +extern struct rmobile_pm_domain r8a7740_pd_a4lc; +#endif /* CONFIG_PM */ + #endif /* __ASM_R8A7740_H__ */ diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h index 915d0093da0..b59048e6d8f 100644 --- a/arch/arm/mach-shmobile/include/mach/sh7372.h +++ b/arch/arm/mach-shmobile/include/mach/sh7372.h @@ -13,6 +13,7 @@ #include <linux/sh_clk.h> #include <linux/pm_domain.h> +#include <mach/pm-rmobile.h> /* * Pin Function Controller: @@ -477,42 +478,16 @@ extern struct clk sh7372_fsibck_clk; extern struct clk sh7372_fsidiva_clk; extern struct clk sh7372_fsidivb_clk; -struct platform_device; - -struct sh7372_pm_domain { - struct generic_pm_domain genpd; - struct dev_power_governor *gov; - int (*suspend)(void); - void (*resume)(void); - unsigned int bit_shift; - bool no_debug; -}; - -static inline struct sh7372_pm_domain *to_sh7372_pd(struct generic_pm_domain *d) -{ - return container_of(d, struct sh7372_pm_domain, genpd); -} - #ifdef CONFIG_PM -extern struct sh7372_pm_domain sh7372_a4lc; -extern struct sh7372_pm_domain sh7372_a4mp; -extern struct sh7372_pm_domain sh7372_d4; -extern struct sh7372_pm_domain sh7372_a4r; -extern struct sh7372_pm_domain sh7372_a3rv; -extern struct sh7372_pm_domain sh7372_a3ri; -extern struct sh7372_pm_domain sh7372_a4s; -extern struct sh7372_pm_domain sh7372_a3sp; -extern struct sh7372_pm_domain sh7372_a3sg; - -extern void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd); -extern void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd, - struct platform_device *pdev); -extern void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd, - struct sh7372_pm_domain *sh7372_sd); -#else -#define sh7372_init_pm_domain(pd) do { } while(0) -#define sh7372_add_device_to_domain(pd, pdev) do { } while(0) -#define sh7372_pm_add_subdomain(pd, sd) do { } while(0) +extern struct rmobile_pm_domain sh7372_pd_a4lc; +extern struct rmobile_pm_domain sh7372_pd_a4mp; +extern struct rmobile_pm_domain sh7372_pd_d4; +extern struct rmobile_pm_domain sh7372_pd_a4r; +extern struct rmobile_pm_domain sh7372_pd_a3rv; +extern struct rmobile_pm_domain sh7372_pd_a3ri; +extern struct rmobile_pm_domain sh7372_pd_a4s; +extern struct rmobile_pm_domain sh7372_pd_a3sp; +extern struct rmobile_pm_domain sh7372_pd_a3sg; #endif /* CONFIG_PM */ extern void sh7372_intcs_suspend(void); diff --git a/arch/arm/mach-shmobile/include/mach/sh73a0.h b/arch/arm/mach-shmobile/include/mach/sh73a0.h index 398e2c10913..fe950f25d79 100644 --- a/arch/arm/mach-shmobile/include/mach/sh73a0.h +++ b/arch/arm/mach-shmobile/include/mach/sh73a0.h @@ -516,6 +516,13 @@ enum { SHDMA_SLAVE_SDHI2_RX, SHDMA_SLAVE_MMCIF_TX, SHDMA_SLAVE_MMCIF_RX, + SHDMA_SLAVE_FSI2A_TX, + SHDMA_SLAVE_FSI2A_RX, + SHDMA_SLAVE_FSI2B_TX, + SHDMA_SLAVE_FSI2B_RX, + SHDMA_SLAVE_FSI2C_TX, + SHDMA_SLAVE_FSI2C_RX, + SHDMA_SLAVE_FSI2D_RX, }; /* diff --git a/arch/arm/mach-shmobile/intc-r8a7740.c b/arch/arm/mach-shmobile/intc-r8a7740.c index 09c42afcb22..9a69a31918b 100644 --- a/arch/arm/mach-shmobile/intc-r8a7740.c +++ b/arch/arm/mach-shmobile/intc-r8a7740.c @@ -71,10 +71,12 @@ enum { DMAC3_1_DEI0, DMAC3_1_DEI1, DMAC3_1_DEI2, DMAC3_1_DEI3, DMAC3_2_DEI4, DMAC3_2_DEI5, DMAC3_2_DADERR, SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM, + HDMI, USBH_INT, USBH_OHCI, USBH_EHCI, USBH_PME, USBH_BIND, RSPI_OVRF, RSPI_SPTEF, RSPI_SPRF, SPU2_0, SPU2_1, FSI, FMSI, + HDMI_SSS, HDMI_KEY, IPMMU, AP_ARM_CTIIRQ, AP_ARM_PMURQ, MFIS2, @@ -182,6 +184,7 @@ static struct intc_vect intca_vectors[] __initdata = { INTC_VECT(USBH_EHCI, 0x1580), INTC_VECT(USBH_PME, 0x15A0), INTC_VECT(USBH_BIND, 0x15C0), + INTC_VECT(HDMI, 0x1700), INTC_VECT(RSPI_OVRF, 0x1780), INTC_VECT(RSPI_SPTEF, 0x17A0), INTC_VECT(RSPI_SPRF, 0x17C0), @@ -189,6 +192,8 @@ static struct intc_vect intca_vectors[] __initdata = { INTC_VECT(SPU2_1, 0x1820), INTC_VECT(FSI, 0x1840), INTC_VECT(FMSI, 0x1860), + INTC_VECT(HDMI_SSS, 0x18A0), + INTC_VECT(HDMI_KEY, 0x18C0), INTC_VECT(IPMMU, 0x1920), INTC_VECT(AP_ARM_CTIIRQ, 0x1980), INTC_VECT(AP_ARM_PMURQ, 0x19A0), @@ -304,11 +309,11 @@ static struct intc_mask_reg intca_mask_registers[] __initdata = { USBH_EHCI, USBH_PME, USBH_BIND, 0 } }, /* IMR3A3 / IMCR3A3 */ { /* IMR4A3 / IMCR4A3 */ 0xe6950090, 0xe69500d0, 8, - { 0, 0, 0, 0, + { HDMI, 0, 0, 0, RSPI_OVRF, RSPI_SPTEF, RSPI_SPRF, 0 } }, { /* IMR5A3 / IMCR5A3 */ 0xe6950094, 0xe69500d4, 8, { SPU2_0, SPU2_1, FSI, FMSI, - 0, 0, 0, 0 } }, + 0, HDMI_SSS, HDMI_KEY, 0 } }, { /* IMR6A3 / IMCR6A3 */ 0xe6950098, 0xe69500d8, 8, { 0, IPMMU, 0, 0, AP_ARM_CTIIRQ, AP_ARM_PMURQ, 0, 0 } }, @@ -353,10 +358,10 @@ static struct intc_prio_reg intca_prio_registers[] __initdata = { { 0xe6950014, 0, 16, 4, /* IPRFA3 */ { USBH2, 0, 0, 0 } }, /* IPRGA3 */ /* IPRHA3 */ - /* IPRIA3 */ + { 0xe6950020, 0, 16, 4, /* IPRIA3 */ { HDMI, 0, 0, 0 } }, { 0xe6950024, 0, 16, 4, /* IPRJA3 */ { RSPI, 0, 0, 0 } }, { 0xe6950028, 0, 16, 4, /* IPRKA3 */ { SPU2, 0, FSI, FMSI } }, - /* IPRLA3 */ + { 0xe695002c, 0, 16, 4, /* IPRLA3 */ { 0, HDMI_SSS, HDMI_KEY, 0 } }, { 0xe6950030, 0, 16, 4, /* IPRMA3 */ { IPMMU, 0, 0, 0 } }, { 0xe6950034, 0, 16, 4, /* IPRNA3 */ { AP_ARM2, 0, 0, 0 } }, { 0xe6950038, 0, 16, 4, /* IPROA3 */ { MFIS2, CPORTR2S, diff --git a/arch/arm/mach-shmobile/pfc-r8a7740.c b/arch/arm/mach-shmobile/pfc-r8a7740.c index 670fe1869db..ce9e7fa5cc8 100644 --- a/arch/arm/mach-shmobile/pfc-r8a7740.c +++ b/arch/arm/mach-shmobile/pfc-r8a7740.c @@ -169,7 +169,7 @@ enum { DBGMD10_MARK, DBGMD11_MARK, DBGMD20_MARK, DBGMD21_MARK, - /* FSI */ + /* FSI-A */ FSIAISLD_PORT0_MARK, /* FSIAISLD Port 0/5 */ FSIAISLD_PORT5_MARK, FSIASPDIF_PORT9_MARK, /* FSIASPDIF Port 9/18 */ @@ -178,6 +178,9 @@ enum { FSIAOBT_MARK, FSIAOSLD_MARK, FSIAOMC_MARK, FSIACK_MARK, FSIAILR_MARK, FSIAIBT_MARK, + /* FSI-B */ + FSIBCK_MARK, + /* FMSI */ FMSISLD_PORT1_MARK, /* FMSISLD Port 1/6 */ FMSISLD_PORT6_MARK, @@ -560,6 +563,9 @@ enum { /* SDENC */ SDENC_CPG_MARK, SDENC_DV_CLKI_MARK, + /* HDMI */ + HDMI_HPD_MARK, HDMI_CEC_MARK, + /* DEBUG */ EDEBGREQ_PULLUP_MARK, /* for JTAG */ EDEBGREQ_PULLDOWN_MARK, @@ -771,6 +777,7 @@ static pinmux_enum_t pinmux_data[] = { /* Port11 */ PINMUX_DATA(FSIACK_MARK, PORT11_FN1), + PINMUX_DATA(FSIBCK_MARK, PORT11_FN2), PINMUX_DATA(IRQ2_PORT11_MARK, PORT11_FN0, MSEL1CR_2_0), /* Port12 */ @@ -1254,7 +1261,7 @@ static pinmux_enum_t pinmux_data[] = { PINMUX_DATA(A21_MARK, PORT120_FN1), PINMUX_DATA(MSIOF0_RSYNC_MARK, PORT120_FN2), PINMUX_DATA(MSIOF1_TSYNC_PORT120_MARK, PORT120_FN3, MSEL4CR_10_0), - PINMUX_DATA(IRQ7_PORT120_MARK, PORT120_FN0, MSEL1CR_7_0), + PINMUX_DATA(IRQ7_PORT120_MARK, PORT120_FN0, MSEL1CR_7_1), /* Port121 */ PINMUX_DATA(A20_MARK, PORT121_FN1), @@ -1616,13 +1623,15 @@ static pinmux_enum_t pinmux_data[] = { /* Port209 */ PINMUX_DATA(VBUS_MARK, PORT209_FN1), - PINMUX_DATA(IRQ7_PORT209_MARK, PORT209_FN0, MSEL1CR_7_1), + PINMUX_DATA(IRQ7_PORT209_MARK, PORT209_FN0, MSEL1CR_7_0), /* Port210 */ PINMUX_DATA(IRQ9_PORT210_MARK, PORT210_FN0, MSEL1CR_9_1), + PINMUX_DATA(HDMI_HPD_MARK, PORT210_FN1), /* Port211 */ PINMUX_DATA(IRQ16_PORT211_MARK, PORT211_FN0, MSEL1CR_16_1), + PINMUX_DATA(HDMI_CEC_MARK, PORT211_FN1), /* LCDC select */ PINMUX_DATA(LCDC0_SELECT_MARK, MSEL3CR_6_0), @@ -1691,7 +1700,7 @@ static struct pinmux_gpio pinmux_gpios[] = { GPIO_FN(DBGMD10), GPIO_FN(DBGMD11), GPIO_FN(DBGMD20), GPIO_FN(DBGMD21), - /* FSI */ + /* FSI-A */ GPIO_FN(FSIAISLD_PORT0), /* FSIAISLD Port 0/5 */ GPIO_FN(FSIAISLD_PORT5), GPIO_FN(FSIASPDIF_PORT9), /* FSIASPDIF Port 9/18 */ @@ -1700,6 +1709,9 @@ static struct pinmux_gpio pinmux_gpios[] = { GPIO_FN(FSIAOBT), GPIO_FN(FSIAOSLD), GPIO_FN(FSIAOMC), GPIO_FN(FSIACK), GPIO_FN(FSIAILR), GPIO_FN(FSIAIBT), + /* FSI-B */ + GPIO_FN(FSIBCK), + /* FMSI */ GPIO_FN(FMSISLD_PORT1), /* FMSISLD Port 1/6 */ GPIO_FN(FMSISLD_PORT6), @@ -2097,6 +2109,10 @@ static struct pinmux_gpio pinmux_gpios[] = { GPIO_FN(SDENC_CPG), GPIO_FN(SDENC_DV_CLKI), + /* HDMI */ + GPIO_FN(HDMI_HPD), + GPIO_FN(HDMI_CEC), + /* SYSC */ GPIO_FN(RESETP_PULLUP), GPIO_FN(RESETP_PLAIN), diff --git a/arch/arm/mach-shmobile/pm-r8a7740.c b/arch/arm/mach-shmobile/pm-r8a7740.c new file mode 100644 index 00000000000..893504d012a --- /dev/null +++ b/arch/arm/mach-shmobile/pm-r8a7740.c @@ -0,0 +1,54 @@ +/* + * r8a7740 power management support + * + * Copyright (C) 2012 Renesas Solutions Corp. + * Copyright (C) 2012 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/console.h> +#include <mach/pm-rmobile.h> + +#ifdef CONFIG_PM +static int r8a7740_pd_a4s_suspend(void) +{ + /* + * The A4S domain contains the CPU core and therefore it should + * only be turned off if the CPU is in use. + */ + return -EBUSY; +} + +struct rmobile_pm_domain r8a7740_pd_a4s = { + .genpd.name = "A4S", + .bit_shift = 10, + .gov = &pm_domain_always_on_gov, + .no_debug = true, + .suspend = r8a7740_pd_a4s_suspend, +}; + +static int r8a7740_pd_a3sp_suspend(void) +{ + /* + * Serial consoles make use of SCIF hardware located in A3SP, + * keep such power domain on if "no_console_suspend" is set. + */ + return console_suspend_enabled ? 0 : -EBUSY; +} + +struct rmobile_pm_domain r8a7740_pd_a3sp = { + .genpd.name = "A3SP", + .bit_shift = 11, + .gov = &pm_domain_always_on_gov, + .no_debug = true, + .suspend = r8a7740_pd_a3sp_suspend, +}; + +struct rmobile_pm_domain r8a7740_pd_a4lc = { + .genpd.name = "A4LC", + .bit_shift = 1, +}; + +#endif /* CONFIG_PM */ diff --git a/arch/arm/mach-shmobile/pm-rmobile.c b/arch/arm/mach-shmobile/pm-rmobile.c new file mode 100644 index 00000000000..a8562540f1d --- /dev/null +++ b/arch/arm/mach-shmobile/pm-rmobile.c @@ -0,0 +1,167 @@ +/* + * rmobile power management support + * + * Copyright (C) 2012 Renesas Solutions Corp. + * Copyright (C) 2012 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + * + * based on pm-sh7372.c + * Copyright (C) 2011 Magnus Damm + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/pm_clock.h> +#include <asm/io.h> +#include <mach/pm-rmobile.h> + +/* SYSC */ +#define SPDCR 0xe6180008 +#define SWUCR 0xe6180014 +#define PSTR 0xe6180080 + +#define PSTR_RETRIES 100 +#define PSTR_DELAY_US 10 + +#ifdef CONFIG_PM +static int rmobile_pd_power_down(struct generic_pm_domain *genpd) +{ + struct rmobile_pm_domain *rmobile_pd = to_rmobile_pd(genpd); + unsigned int mask = 1 << rmobile_pd->bit_shift; + + if (rmobile_pd->suspend) { + int ret = rmobile_pd->suspend(); + + if (ret) + return ret; + } + + if (__raw_readl(PSTR) & mask) { + unsigned int retry_count; + __raw_writel(mask, SPDCR); + + for (retry_count = PSTR_RETRIES; retry_count; retry_count--) { + if (!(__raw_readl(SPDCR) & mask)) + break; + cpu_relax(); + } + } + + if (!rmobile_pd->no_debug) + pr_debug("%s: Power off, 0x%08x -> PSTR = 0x%08x\n", + genpd->name, mask, __raw_readl(PSTR)); + + return 0; +} + +static int __rmobile_pd_power_up(struct rmobile_pm_domain *rmobile_pd, + bool do_resume) +{ + unsigned int mask = 1 << rmobile_pd->bit_shift; + unsigned int retry_count; + int ret = 0; + + if (__raw_readl(PSTR) & mask) + goto out; + + __raw_writel(mask, SWUCR); + + for (retry_count = 2 * PSTR_RETRIES; retry_count; retry_count--) { + if (!(__raw_readl(SWUCR) & mask)) + break; + if (retry_count > PSTR_RETRIES) + udelay(PSTR_DELAY_US); + else + cpu_relax(); + } + if (!retry_count) + ret = -EIO; + + if (!rmobile_pd->no_debug) + pr_debug("%s: Power on, 0x%08x -> PSTR = 0x%08x\n", + rmobile_pd->genpd.name, mask, __raw_readl(PSTR)); + +out: + if (ret == 0 && rmobile_pd->resume && do_resume) + rmobile_pd->resume(); + + return ret; +} + +static int rmobile_pd_power_up(struct generic_pm_domain *genpd) +{ + return __rmobile_pd_power_up(to_rmobile_pd(genpd), true); +} + +static bool rmobile_pd_active_wakeup(struct device *dev) +{ + bool (*active_wakeup)(struct device *dev); + + active_wakeup = dev_gpd_data(dev)->ops.active_wakeup; + return active_wakeup ? active_wakeup(dev) : true; +} + +static int rmobile_pd_stop_dev(struct device *dev) +{ + int (*stop)(struct device *dev); + + stop = dev_gpd_data(dev)->ops.stop; + if (stop) { + int ret = stop(dev); + if (ret) + return ret; + } + return pm_clk_suspend(dev); +} + +static int rmobile_pd_start_dev(struct device *dev) +{ + int (*start)(struct device *dev); + int ret; + + ret = pm_clk_resume(dev); + if (ret) + return ret; + + start = dev_gpd_data(dev)->ops.start; + if (start) + ret = start(dev); + + return ret; +} + +void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd) +{ + struct generic_pm_domain *genpd = &rmobile_pd->genpd; + struct dev_power_governor *gov = rmobile_pd->gov; + + pm_genpd_init(genpd, gov ? : &simple_qos_governor, false); + genpd->dev_ops.stop = rmobile_pd_stop_dev; + genpd->dev_ops.start = rmobile_pd_start_dev; + genpd->dev_ops.active_wakeup = rmobile_pd_active_wakeup; + genpd->dev_irq_safe = true; + genpd->power_off = rmobile_pd_power_down; + genpd->power_on = rmobile_pd_power_up; + __rmobile_pd_power_up(rmobile_pd, false); +} + +void rmobile_add_device_to_domain(struct rmobile_pm_domain *rmobile_pd, + struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + + pm_genpd_add_device(&rmobile_pd->genpd, dev); + if (pm_clk_no_clocks(dev)) + pm_clk_add(dev, NULL); +} + +void rmobile_pm_add_subdomain(struct rmobile_pm_domain *rmobile_pd, + struct rmobile_pm_domain *rmobile_sd) +{ + pm_genpd_add_subdomain(&rmobile_pd->genpd, &rmobile_sd->genpd); +} +#endif /* CONFIG_PM */ diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c index a3bdb12acde..79203706922 100644 --- a/arch/arm/mach-shmobile/pm-sh7372.c +++ b/arch/arm/mach-shmobile/pm-sh7372.c @@ -26,6 +26,7 @@ #include <asm/suspend.h> #include <mach/common.h> #include <mach/sh7372.h> +#include <mach/pm-rmobile.h> /* DBG */ #define DBGREG1 0xe6100020 @@ -41,13 +42,10 @@ #define PLLC01STPCR 0xe61500c8 /* SYSC */ -#define SPDCR 0xe6180008 -#define SWUCR 0xe6180014 #define SBAR 0xe6180020 #define WUPRMSK 0xe6180028 #define WUPSMSK 0xe618002c #define WUPSMSK2 0xe6180048 -#define PSTR 0xe6180080 #define WUPSFAC 0xe6180098 #define IRQCR 0xe618022c #define IRQCR2 0xe6180238 @@ -71,188 +69,48 @@ /* AP-System Core */ #define APARMBAREA 0xe6f10020 -#define PSTR_RETRIES 100 -#define PSTR_DELAY_US 10 - #ifdef CONFIG_PM -static int pd_power_down(struct generic_pm_domain *genpd) -{ - struct sh7372_pm_domain *sh7372_pd = to_sh7372_pd(genpd); - unsigned int mask = 1 << sh7372_pd->bit_shift; - - if (sh7372_pd->suspend) { - int ret = sh7372_pd->suspend(); - - if (ret) - return ret; - } - - if (__raw_readl(PSTR) & mask) { - unsigned int retry_count; - - __raw_writel(mask, SPDCR); - - for (retry_count = PSTR_RETRIES; retry_count; retry_count--) { - if (!(__raw_readl(SPDCR) & mask)) - break; - cpu_relax(); - } - } - - if (!sh7372_pd->no_debug) - pr_debug("%s: Power off, 0x%08x -> PSTR = 0x%08x\n", - genpd->name, mask, __raw_readl(PSTR)); - - return 0; -} - -static int __pd_power_up(struct sh7372_pm_domain *sh7372_pd, bool do_resume) -{ - unsigned int mask = 1 << sh7372_pd->bit_shift; - unsigned int retry_count; - int ret = 0; - - if (__raw_readl(PSTR) & mask) - goto out; - - __raw_writel(mask, SWUCR); - - for (retry_count = 2 * PSTR_RETRIES; retry_count; retry_count--) { - if (!(__raw_readl(SWUCR) & mask)) - break; - if (retry_count > PSTR_RETRIES) - udelay(PSTR_DELAY_US); - else - cpu_relax(); - } - if (!retry_count) - ret = -EIO; - - if (!sh7372_pd->no_debug) - pr_debug("%s: Power on, 0x%08x -> PSTR = 0x%08x\n", - sh7372_pd->genpd.name, mask, __raw_readl(PSTR)); - - out: - if (ret == 0 && sh7372_pd->resume && do_resume) - sh7372_pd->resume(); - - return ret; -} - -static int pd_power_up(struct generic_pm_domain *genpd) -{ - return __pd_power_up(to_sh7372_pd(genpd), true); -} - -static int sh7372_a4r_suspend(void) -{ - sh7372_intcs_suspend(); - __raw_writel(0x300fffff, WUPRMSK); /* avoid wakeup */ - return 0; -} - -static bool pd_active_wakeup(struct device *dev) -{ - bool (*active_wakeup)(struct device *dev); - - active_wakeup = dev_gpd_data(dev)->ops.active_wakeup; - return active_wakeup ? active_wakeup(dev) : true; -} - -static int sh7372_stop_dev(struct device *dev) -{ - int (*stop)(struct device *dev); - - stop = dev_gpd_data(dev)->ops.stop; - if (stop) { - int ret = stop(dev); - if (ret) - return ret; - } - return pm_clk_suspend(dev); -} - -static int sh7372_start_dev(struct device *dev) -{ - int (*start)(struct device *dev); - int ret; - - ret = pm_clk_resume(dev); - if (ret) - return ret; - - start = dev_gpd_data(dev)->ops.start; - if (start) - ret = start(dev); - - return ret; -} - -void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd) -{ - struct generic_pm_domain *genpd = &sh7372_pd->genpd; - struct dev_power_governor *gov = sh7372_pd->gov; - - pm_genpd_init(genpd, gov ? : &simple_qos_governor, false); - genpd->dev_ops.stop = sh7372_stop_dev; - genpd->dev_ops.start = sh7372_start_dev; - genpd->dev_ops.active_wakeup = pd_active_wakeup; - genpd->dev_irq_safe = true; - genpd->power_off = pd_power_down; - genpd->power_on = pd_power_up; - __pd_power_up(sh7372_pd, false); -} - -void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd, - struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - - pm_genpd_add_device(&sh7372_pd->genpd, dev); - if (pm_clk_no_clocks(dev)) - pm_clk_add(dev, NULL); -} - -void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd, - struct sh7372_pm_domain *sh7372_sd) -{ - pm_genpd_add_subdomain(&sh7372_pd->genpd, &sh7372_sd->genpd); -} - -struct sh7372_pm_domain sh7372_a4lc = { +struct rmobile_pm_domain sh7372_pd_a4lc = { .genpd.name = "A4LC", .bit_shift = 1, }; -struct sh7372_pm_domain sh7372_a4mp = { +struct rmobile_pm_domain sh7372_pd_a4mp = { .genpd.name = "A4MP", .bit_shift = 2, }; -struct sh7372_pm_domain sh7372_d4 = { +struct rmobile_pm_domain sh7372_pd_d4 = { .genpd.name = "D4", .bit_shift = 3, }; -struct sh7372_pm_domain sh7372_a4r = { +static int sh7372_a4r_pd_suspend(void) +{ + sh7372_intcs_suspend(); + __raw_writel(0x300fffff, WUPRMSK); /* avoid wakeup */ + return 0; +} + +struct rmobile_pm_domain sh7372_pd_a4r = { .genpd.name = "A4R", .bit_shift = 5, - .suspend = sh7372_a4r_suspend, + .suspend = sh7372_a4r_pd_suspend, .resume = sh7372_intcs_resume, }; -struct sh7372_pm_domain sh7372_a3rv = { +struct rmobile_pm_domain sh7372_pd_a3rv = { .genpd.name = "A3RV", .bit_shift = 6, }; -struct sh7372_pm_domain sh7372_a3ri = { +struct rmobile_pm_domain sh7372_pd_a3ri = { .genpd.name = "A3RI", .bit_shift = 8, }; -static int sh7372_a4s_suspend(void) +static int sh7372_pd_a4s_suspend(void) { /* * The A4S domain contains the CPU core and therefore it should @@ -261,15 +119,15 @@ static int sh7372_a4s_suspend(void) return -EBUSY; } -struct sh7372_pm_domain sh7372_a4s = { +struct rmobile_pm_domain sh7372_pd_a4s = { .genpd.name = "A4S", .bit_shift = 10, .gov = &pm_domain_always_on_gov, .no_debug = true, - .suspend = sh7372_a4s_suspend, + .suspend = sh7372_pd_a4s_suspend, }; -static int sh7372_a3sp_suspend(void) +static int sh7372_a3sp_pd_suspend(void) { /* * Serial consoles make use of SCIF hardware located in A3SP, @@ -278,32 +136,22 @@ static int sh7372_a3sp_suspend(void) return console_suspend_enabled ? 0 : -EBUSY; } -struct sh7372_pm_domain sh7372_a3sp = { +struct rmobile_pm_domain sh7372_pd_a3sp = { .genpd.name = "A3SP", .bit_shift = 11, .gov = &pm_domain_always_on_gov, .no_debug = true, - .suspend = sh7372_a3sp_suspend, + .suspend = sh7372_a3sp_pd_suspend, }; -struct sh7372_pm_domain sh7372_a3sg = { +struct rmobile_pm_domain sh7372_pd_a3sg = { .genpd.name = "A3SG", .bit_shift = 13, }; -#else /* !CONFIG_PM */ - -static inline void sh7372_a3sp_init(void) {} - -#endif /* !CONFIG_PM */ +#endif /* CONFIG_PM */ #if defined(CONFIG_SUSPEND) || defined(CONFIG_CPU_IDLE) -static int sh7372_do_idle_core_standby(unsigned long unused) -{ - cpu_do_idle(); /* WFI when SYSTBCR == 0x10 -> Core Standby */ - return 0; -} - static void sh7372_set_reset_vector(unsigned long address) { /* set reset vector, translate 4k */ @@ -311,21 +159,6 @@ static void sh7372_set_reset_vector(unsigned long address) __raw_writel(0, APARMBAREA); } -static void sh7372_enter_core_standby(void) -{ - sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc)); - - /* enter sleep mode with SYSTBCR to 0x10 */ - __raw_writel(0x10, SYSTBCR); - cpu_suspend(0, sh7372_do_idle_core_standby); - __raw_writel(0, SYSTBCR); - - /* disable reset vector translation */ - __raw_writel(0, SBAR); -} -#endif - -#ifdef CONFIG_SUSPEND static void sh7372_enter_sysc(int pllc0_on, unsigned long sleep_mode) { if (pllc0_on) @@ -465,22 +298,42 @@ static void sh7372_setup_sysc(unsigned long msk, unsigned long msk2) static void sh7372_enter_a3sm_common(int pllc0_on) { + /* use INTCA together with SYSC for wakeup */ + sh7372_setup_sysc(1 << 0, 0); sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc)); sh7372_enter_sysc(pllc0_on, 1 << 12); } +#endif /* CONFIG_SUSPEND || CONFIG_CPU_IDLE */ -static void sh7372_enter_a4s_common(int pllc0_on) +#ifdef CONFIG_CPU_IDLE +static int sh7372_do_idle_core_standby(unsigned long unused) { - sh7372_intca_suspend(); - memcpy((void *)SMFRAM, sh7372_resume_core_standby_sysc, 0x100); - sh7372_set_reset_vector(SMFRAM); - sh7372_enter_sysc(pllc0_on, 1 << 10); - sh7372_intca_resume(); + cpu_do_idle(); /* WFI when SYSTBCR == 0x10 -> Core Standby */ + return 0; } -#endif +static void sh7372_enter_core_standby(void) +{ + sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc)); -#ifdef CONFIG_CPU_IDLE + /* enter sleep mode with SYSTBCR to 0x10 */ + __raw_writel(0x10, SYSTBCR); + cpu_suspend(0, sh7372_do_idle_core_standby); + __raw_writel(0, SYSTBCR); + + /* disable reset vector translation */ + __raw_writel(0, SBAR); +} + +static void sh7372_enter_a3sm_pll_on(void) +{ + sh7372_enter_a3sm_common(1); +} + +static void sh7372_enter_a3sm_pll_off(void) +{ + sh7372_enter_a3sm_common(0); +} static void sh7372_cpuidle_setup(struct cpuidle_driver *drv) { @@ -492,7 +345,24 @@ static void sh7372_cpuidle_setup(struct cpuidle_driver *drv) state->target_residency = 20 + 10; state->flags = CPUIDLE_FLAG_TIME_VALID; shmobile_cpuidle_modes[drv->state_count] = sh7372_enter_core_standby; + drv->state_count++; + + state = &drv->states[drv->state_count]; + snprintf(state->name, CPUIDLE_NAME_LEN, "C3"); + strncpy(state->desc, "A3SM PLL ON", CPUIDLE_DESC_LEN); + state->exit_latency = 20; + state->target_residency = 30 + 20; + state->flags = CPUIDLE_FLAG_TIME_VALID; + shmobile_cpuidle_modes[drv->state_count] = sh7372_enter_a3sm_pll_on; + drv->state_count++; + state = &drv->states[drv->state_count]; + snprintf(state->name, CPUIDLE_NAME_LEN, "C4"); + strncpy(state->desc, "A3SM PLL OFF", CPUIDLE_DESC_LEN); + state->exit_latency = 120; + state->target_residency = 30 + 120; + state->flags = CPUIDLE_FLAG_TIME_VALID; + shmobile_cpuidle_modes[drv->state_count] = sh7372_enter_a3sm_pll_off; drv->state_count++; } @@ -505,6 +375,14 @@ static void sh7372_cpuidle_init(void) {} #endif #ifdef CONFIG_SUSPEND +static void sh7372_enter_a4s_common(int pllc0_on) +{ + sh7372_intca_suspend(); + memcpy((void *)SMFRAM, sh7372_resume_core_standby_sysc, 0x100); + sh7372_set_reset_vector(SMFRAM); + sh7372_enter_sysc(pllc0_on, 1 << 10); + sh7372_intca_resume(); +} static int sh7372_enter_suspend(suspend_state_t suspend_state) { @@ -512,24 +390,21 @@ static int sh7372_enter_suspend(suspend_state_t suspend_state) /* check active clocks to determine potential wakeup sources */ if (sh7372_sysc_valid(&msk, &msk2)) { - /* convert INTC mask and sense to SYSC mask and sense */ - sh7372_setup_sysc(msk, msk2); - if (!console_suspend_enabled && - sh7372_a4s.genpd.status == GPD_STATE_POWER_OFF) { + sh7372_pd_a4s.genpd.status == GPD_STATE_POWER_OFF) { + /* convert INTC mask/sense to SYSC mask/sense */ + sh7372_setup_sysc(msk, msk2); + /* enter A4S sleep with PLLC0 off */ pr_debug("entering A4S\n"); sh7372_enter_a4s_common(0); - } else { - /* enter A3SM sleep with PLLC0 off */ - pr_debug("entering A3SM\n"); - sh7372_enter_a3sm_common(0); + return 0; } - } else { - /* default to Core Standby that supports all wakeup sources */ - pr_debug("entering Core Standby\n"); - sh7372_enter_core_standby(); } + + /* default to enter A3SM sleep with PLLC0 off */ + pr_debug("entering A3SM\n"); + sh7372_enter_a3sm_common(0); return 0; } @@ -550,7 +425,7 @@ static int sh7372_pm_notifier_fn(struct notifier_block *notifier, * executed during system suspend and resume, respectively, so * that those functions don't crash while accessing the INTCS. */ - pm_genpd_poweron(&sh7372_a4r.genpd); + pm_genpd_poweron(&sh7372_pd_a4r.genpd); break; case PM_POST_SUSPEND: pm_genpd_poweroff_unused(); diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c index ec4eb49c169..78948a9dba0 100644 --- a/arch/arm/mach-shmobile/setup-r8a7740.c +++ b/arch/arm/mach-shmobile/setup-r8a7740.c @@ -23,9 +23,14 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/platform_device.h> +#include <linux/of_platform.h> #include <linux/serial_sci.h> +#include <linux/sh_dma.h> #include <linux/sh_timer.h> +#include <linux/dma-mapping.h> +#include <mach/dma-register.h> #include <mach/r8a7740.h> +#include <mach/pm-rmobile.h> #include <mach/common.h> #include <mach/irqs.h> #include <asm/mach-types.h> @@ -276,6 +281,272 @@ static struct platform_device *r8a7740_early_devices[] __initdata = { &cmt10_device, }; +/* DMA */ +static const struct sh_dmae_slave_config r8a7740_dmae_slaves[] = { + { + .slave_id = SHDMA_SLAVE_SDHI0_TX, + .addr = 0xe6850030, + .chcr = CHCR_TX(XMIT_SZ_16BIT), + .mid_rid = 0xc1, + }, { + .slave_id = SHDMA_SLAVE_SDHI0_RX, + .addr = 0xe6850030, + .chcr = CHCR_RX(XMIT_SZ_16BIT), + .mid_rid = 0xc2, + }, { + .slave_id = SHDMA_SLAVE_SDHI1_TX, + .addr = 0xe6860030, + .chcr = CHCR_TX(XMIT_SZ_16BIT), + .mid_rid = 0xc9, + }, { + .slave_id = SHDMA_SLAVE_SDHI1_RX, + .addr = 0xe6860030, + .chcr = CHCR_RX(XMIT_SZ_16BIT), + .mid_rid = 0xca, + }, { + .slave_id = SHDMA_SLAVE_SDHI2_TX, + .addr = 0xe6870030, + .chcr = CHCR_TX(XMIT_SZ_16BIT), + .mid_rid = 0xcd, + }, { + .slave_id = SHDMA_SLAVE_SDHI2_RX, + .addr = 0xe6870030, + .chcr = CHCR_RX(XMIT_SZ_16BIT), + .mid_rid = 0xce, + }, { + .slave_id = SHDMA_SLAVE_FSIA_TX, + .addr = 0xfe1f0024, + .chcr = CHCR_TX(XMIT_SZ_32BIT), + .mid_rid = 0xb1, + }, { + .slave_id = SHDMA_SLAVE_FSIA_RX, + .addr = 0xfe1f0020, + .chcr = CHCR_RX(XMIT_SZ_32BIT), + .mid_rid = 0xb2, + }, { + .slave_id = SHDMA_SLAVE_FSIB_TX, + .addr = 0xfe1f0064, + .chcr = CHCR_TX(XMIT_SZ_32BIT), + .mid_rid = 0xb5, + }, +}; + +#define DMA_CHANNEL(a, b, c) \ +{ \ + .offset = a, \ + .dmars = b, \ + .dmars_bit = c, \ + .chclr_offset = (0x220 - 0x20) + a \ +} + +static const struct sh_dmae_channel r8a7740_dmae_channels[] = { + DMA_CHANNEL(0x00, 0, 0), + DMA_CHANNEL(0x10, 0, 8), + DMA_CHANNEL(0x20, 4, 0), + DMA_CHANNEL(0x30, 4, 8), + DMA_CHANNEL(0x50, 8, 0), + DMA_CHANNEL(0x60, 8, 8), +}; + +static struct sh_dmae_pdata dma_platform_data = { + .slave = r8a7740_dmae_slaves, + .slave_num = ARRAY_SIZE(r8a7740_dmae_slaves), + .channel = r8a7740_dmae_channels, + .channel_num = ARRAY_SIZE(r8a7740_dmae_channels), + .ts_low_shift = TS_LOW_SHIFT, + .ts_low_mask = TS_LOW_BIT << TS_LOW_SHIFT, + .ts_high_shift = TS_HI_SHIFT, + .ts_high_mask = TS_HI_BIT << TS_HI_SHIFT, + .ts_shift = dma_ts_shift, + .ts_shift_num = ARRAY_SIZE(dma_ts_shift), + .dmaor_init = DMAOR_DME, + .chclr_present = 1, +}; + +/* Resource order important! */ +static struct resource r8a7740_dmae0_resources[] = { + { + /* Channel registers and DMAOR */ + .start = 0xfe008020, + .end = 0xfe00828f, + .flags = IORESOURCE_MEM, + }, + { + /* DMARSx */ + .start = 0xfe009000, + .end = 0xfe00900b, + .flags = IORESOURCE_MEM, + }, + { + .name = "error_irq", + .start = evt2irq(0x20c0), + .end = evt2irq(0x20c0), + .flags = IORESOURCE_IRQ, + }, + { + /* IRQ for channels 0-5 */ + .start = evt2irq(0x2000), + .end = evt2irq(0x20a0), + .flags = IORESOURCE_IRQ, + }, +}; + +/* Resource order important! */ +static struct resource r8a7740_dmae1_resources[] = { + { + /* Channel registers and DMAOR */ + .start = 0xfe018020, + .end = 0xfe01828f, + .flags = IORESOURCE_MEM, + }, + { + /* DMARSx */ + .start = 0xfe019000, + .end = 0xfe01900b, + .flags = IORESOURCE_MEM, + }, + { + .name = "error_irq", + .start = evt2irq(0x21c0), + .end = evt2irq(0x21c0), + .flags = IORESOURCE_IRQ, + }, + { + /* IRQ for channels 0-5 */ + .start = evt2irq(0x2100), + .end = evt2irq(0x21a0), + .flags = IORESOURCE_IRQ, + }, +}; + +/* Resource order important! */ +static struct resource r8a7740_dmae2_resources[] = { + { + /* Channel registers and DMAOR */ + .start = 0xfe028020, + .end = 0xfe02828f, + .flags = IORESOURCE_MEM, + }, + { + /* DMARSx */ + .start = 0xfe029000, + .end = 0xfe02900b, + .flags = IORESOURCE_MEM, + }, + { + .name = "error_irq", + .start = evt2irq(0x22c0), + .end = evt2irq(0x22c0), + .flags = IORESOURCE_IRQ, + }, + { + /* IRQ for channels 0-5 */ + .start = evt2irq(0x2200), + .end = evt2irq(0x22a0), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device dma0_device = { + .name = "sh-dma-engine", + .id = 0, + .resource = r8a7740_dmae0_resources, + .num_resources = ARRAY_SIZE(r8a7740_dmae0_resources), + .dev = { + .platform_data = &dma_platform_data, + }, +}; + +static struct platform_device dma1_device = { + .name = "sh-dma-engine", + .id = 1, + .resource = r8a7740_dmae1_resources, + .num_resources = ARRAY_SIZE(r8a7740_dmae1_resources), + .dev = { + .platform_data = &dma_platform_data, + }, +}; + +static struct platform_device dma2_device = { + .name = "sh-dma-engine", + .id = 2, + .resource = r8a7740_dmae2_resources, + .num_resources = ARRAY_SIZE(r8a7740_dmae2_resources), + .dev = { + .platform_data = &dma_platform_data, + }, +}; + +/* USB-DMAC */ +static const struct sh_dmae_channel r8a7740_usb_dma_channels[] = { + { + .offset = 0, + }, { + .offset = 0x20, + }, +}; + +static const struct sh_dmae_slave_config r8a7740_usb_dma_slaves[] = { + { + .slave_id = SHDMA_SLAVE_USBHS_TX, + .chcr = USBTS_INDEX2VAL(USBTS_XMIT_SZ_8BYTE), + }, { + .slave_id = SHDMA_SLAVE_USBHS_RX, + .chcr = USBTS_INDEX2VAL(USBTS_XMIT_SZ_8BYTE), + }, +}; + +static struct sh_dmae_pdata usb_dma_platform_data = { + .slave = r8a7740_usb_dma_slaves, + .slave_num = ARRAY_SIZE(r8a7740_usb_dma_slaves), + .channel = r8a7740_usb_dma_channels, + .channel_num = ARRAY_SIZE(r8a7740_usb_dma_channels), + .ts_low_shift = USBTS_LOW_SHIFT, + .ts_low_mask = USBTS_LOW_BIT << USBTS_LOW_SHIFT, + .ts_high_shift = USBTS_HI_SHIFT, + .ts_high_mask = USBTS_HI_BIT << USBTS_HI_SHIFT, + .ts_shift = dma_usbts_shift, + .ts_shift_num = ARRAY_SIZE(dma_usbts_shift), + .dmaor_init = DMAOR_DME, + .chcr_offset = 0x14, + .chcr_ie_bit = 1 << 5, + .dmaor_is_32bit = 1, + .needs_tend_set = 1, + .no_dmars = 1, + .slave_only = 1, +}; + +static struct resource r8a7740_usb_dma_resources[] = { + { + /* Channel registers and DMAOR */ + .start = 0xe68a0020, + .end = 0xe68a0064 - 1, + .flags = IORESOURCE_MEM, + }, + { + /* VCR/SWR/DMICR */ + .start = 0xe68a0000, + .end = 0xe68a0014 - 1, + .flags = IORESOURCE_MEM, + }, + { + /* IRQ for channels */ + .start = evt2irq(0x0a00), + .end = evt2irq(0x0a00), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device usb_dma_device = { + .name = "sh-dma-engine", + .id = 3, + .resource = r8a7740_usb_dma_resources, + .num_resources = ARRAY_SIZE(r8a7740_usb_dma_resources), + .dev = { + .platform_data = &usb_dma_platform_data, + }, +}; + /* I2C */ static struct resource i2c0_resources[] = { [0] = { @@ -322,8 +593,30 @@ static struct platform_device i2c1_device = { static struct platform_device *r8a7740_late_devices[] __initdata = { &i2c0_device, &i2c1_device, + &dma0_device, + &dma1_device, + &dma2_device, + &usb_dma_device, }; +/* + * r8a7740 chip has lasting errata on MERAM buffer. + * this is work-around for it. + * see + * "Media RAM (MERAM)" on r8a7740 documentation + */ +#define MEBUFCNTR 0xFE950098 +void r8a7740_meram_workaround(void) +{ + void __iomem *reg; + + reg = ioremap_nocache(MEBUFCNTR, 4); + if (reg) { + iowrite32(0x01600164, reg); + iounmap(reg); + } +} + #define ICCR 0x0004 #define ICSTART 0x0070 @@ -380,10 +673,31 @@ void __init r8a7740_add_standard_devices(void) r8a7740_i2c_workaround(&i2c0_device); r8a7740_i2c_workaround(&i2c1_device); + /* PM domain */ + rmobile_init_pm_domain(&r8a7740_pd_a4s); + rmobile_init_pm_domain(&r8a7740_pd_a3sp); + rmobile_init_pm_domain(&r8a7740_pd_a4lc); + + rmobile_pm_add_subdomain(&r8a7740_pd_a4s, &r8a7740_pd_a3sp); + + /* add devices */ platform_add_devices(r8a7740_early_devices, ARRAY_SIZE(r8a7740_early_devices)); platform_add_devices(r8a7740_late_devices, ARRAY_SIZE(r8a7740_late_devices)); + + /* add devices to PM domain */ + + rmobile_add_device_to_domain(&r8a7740_pd_a3sp, &scif0_device); + rmobile_add_device_to_domain(&r8a7740_pd_a3sp, &scif1_device); + rmobile_add_device_to_domain(&r8a7740_pd_a3sp, &scif2_device); + rmobile_add_device_to_domain(&r8a7740_pd_a3sp, &scif3_device); + rmobile_add_device_to_domain(&r8a7740_pd_a3sp, &scif4_device); + rmobile_add_device_to_domain(&r8a7740_pd_a3sp, &scif5_device); + rmobile_add_device_to_domain(&r8a7740_pd_a3sp, &scif6_device); + rmobile_add_device_to_domain(&r8a7740_pd_a3sp, &scif7_device); + rmobile_add_device_to_domain(&r8a7740_pd_a3sp, &scifb_device); + rmobile_add_device_to_domain(&r8a7740_pd_a3sp, &i2c1_device); } static void __init r8a7740_earlytimer_init(void) @@ -403,3 +717,49 @@ void __init r8a7740_add_early_devices(void) /* override timer setup with soc-specific code */ shmobile_timer.init = r8a7740_earlytimer_init; } + +#ifdef CONFIG_USE_OF + +void __init r8a7740_add_early_devices_dt(void) +{ + shmobile_setup_delay(800, 1, 3); /* Cortex-A9 @ 800MHz */ + + early_platform_add_devices(r8a7740_early_devices, + ARRAY_SIZE(r8a7740_early_devices)); + + /* setup early console here as well */ + shmobile_setup_console(); +} + +static const struct of_dev_auxdata r8a7740_auxdata_lookup[] __initconst = { + { } +}; + +void __init r8a7740_add_standard_devices_dt(void) +{ + /* clocks are setup late during boot in the case of DT */ + r8a7740_clock_init(0); + + platform_add_devices(r8a7740_early_devices, + ARRAY_SIZE(r8a7740_early_devices)); + + of_platform_populate(NULL, of_default_bus_match_table, + r8a7740_auxdata_lookup, NULL); +} + +static const char *r8a7740_boards_compat_dt[] __initdata = { + "renesas,r8a7740", + NULL, +}; + +DT_MACHINE_START(SH7372_DT, "Generic R8A7740 (Flattened Device Tree)") + .map_io = r8a7740_map_io, + .init_early = r8a7740_add_early_devices_dt, + .init_irq = r8a7740_init_irq, + .handle_irq = shmobile_handle_irq_intc, + .init_machine = r8a7740_add_standard_devices_dt, + .timer = &shmobile_timer, + .dt_compat = r8a7740_boards_compat_dt, +MACHINE_END + +#endif /* CONFIG_USE_OF */ diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index fafce9ce821..838a87be1d5 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c @@ -33,6 +33,7 @@ #include <linux/sh_timer.h> #include <linux/pm_domain.h> #include <linux/dma-mapping.h> +#include <mach/dma-register.h> #include <mach/hardware.h> #include <mach/irqs.h> #include <mach/sh7372.h> @@ -335,151 +336,126 @@ static struct platform_device iic1_device = { }; /* DMA */ -/* Transmit sizes and respective CHCR register values */ -enum { - XMIT_SZ_8BIT = 0, - XMIT_SZ_16BIT = 1, - XMIT_SZ_32BIT = 2, - XMIT_SZ_64BIT = 7, - XMIT_SZ_128BIT = 3, - XMIT_SZ_256BIT = 4, - XMIT_SZ_512BIT = 5, -}; - -/* log2(size / 8) - used to calculate number of transfers */ -#define TS_SHIFT { \ - [XMIT_SZ_8BIT] = 0, \ - [XMIT_SZ_16BIT] = 1, \ - [XMIT_SZ_32BIT] = 2, \ - [XMIT_SZ_64BIT] = 3, \ - [XMIT_SZ_128BIT] = 4, \ - [XMIT_SZ_256BIT] = 5, \ - [XMIT_SZ_512BIT] = 6, \ -} - -#define TS_INDEX2VAL(i) ((((i) & 3) << 3) | \ - (((i) & 0xc) << (20 - 2))) - static const struct sh_dmae_slave_config sh7372_dmae_slaves[] = { { .slave_id = SHDMA_SLAVE_SCIF0_TX, .addr = 0xe6c40020, - .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT), + .chcr = CHCR_TX(XMIT_SZ_8BIT), .mid_rid = 0x21, }, { .slave_id = SHDMA_SLAVE_SCIF0_RX, .addr = 0xe6c40024, - .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT), + .chcr = CHCR_RX(XMIT_SZ_8BIT), .mid_rid = 0x22, }, { .slave_id = SHDMA_SLAVE_SCIF1_TX, .addr = 0xe6c50020, - .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT), + .chcr = CHCR_TX(XMIT_SZ_8BIT), .mid_rid = 0x25, }, { .slave_id = SHDMA_SLAVE_SCIF1_RX, .addr = 0xe6c50024, - .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT), + .chcr = CHCR_RX(XMIT_SZ_8BIT), .mid_rid = 0x26, }, { .slave_id = SHDMA_SLAVE_SCIF2_TX, .addr = 0xe6c60020, - .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT), + .chcr = CHCR_TX(XMIT_SZ_8BIT), .mid_rid = 0x29, }, { .slave_id = SHDMA_SLAVE_SCIF2_RX, .addr = 0xe6c60024, - .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT), + .chcr = CHCR_RX(XMIT_SZ_8BIT), .mid_rid = 0x2a, }, { .slave_id = SHDMA_SLAVE_SCIF3_TX, .addr = 0xe6c70020, - .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT), + .chcr = CHCR_TX(XMIT_SZ_8BIT), .mid_rid = 0x2d, }, { .slave_id = SHDMA_SLAVE_SCIF3_RX, .addr = 0xe6c70024, - .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT), + .chcr = CHCR_RX(XMIT_SZ_8BIT), .mid_rid = 0x2e, }, { .slave_id = SHDMA_SLAVE_SCIF4_TX, .addr = 0xe6c80020, - .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT), + .chcr = CHCR_TX(XMIT_SZ_8BIT), .mid_rid = 0x39, }, { .slave_id = SHDMA_SLAVE_SCIF4_RX, .addr = 0xe6c80024, - .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT), + .chcr = CHCR_RX(XMIT_SZ_8BIT), .mid_rid = 0x3a, }, { .slave_id = SHDMA_SLAVE_SCIF5_TX, .addr = 0xe6cb0020, - .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT), + .chcr = CHCR_TX(XMIT_SZ_8BIT), .mid_rid = 0x35, }, { .slave_id = SHDMA_SLAVE_SCIF5_RX, .addr = 0xe6cb0024, - .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT), + .chcr = CHCR_RX(XMIT_SZ_8BIT), .mid_rid = 0x36, }, { .slave_id = SHDMA_SLAVE_SCIF6_TX, .addr = 0xe6c30040, - .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT), + .chcr = CHCR_TX(XMIT_SZ_8BIT), .mid_rid = 0x3d, }, { .slave_id = SHDMA_SLAVE_SCIF6_RX, .addr = 0xe6c30060, - .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT), + .chcr = CHCR_RX(XMIT_SZ_8BIT), .mid_rid = 0x3e, }, { .slave_id = SHDMA_SLAVE_SDHI0_TX, .addr = 0xe6850030, - .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT), + .chcr = CHCR_TX(XMIT_SZ_16BIT), .mid_rid = 0xc1, }, { .slave_id = SHDMA_SLAVE_SDHI0_RX, .addr = 0xe6850030, - .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT), + .chcr = CHCR_RX(XMIT_SZ_16BIT), .mid_rid = 0xc2, }, { .slave_id = SHDMA_SLAVE_SDHI1_TX, .addr = 0xe6860030, - .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT), + .chcr = CHCR_TX(XMIT_SZ_16BIT), .mid_rid = 0xc9, }, { .slave_id = SHDMA_SLAVE_SDHI1_RX, .addr = 0xe6860030, - .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT), + .chcr = CHCR_RX(XMIT_SZ_16BIT), .mid_rid = 0xca, }, { .slave_id = SHDMA_SLAVE_SDHI2_TX, .addr = 0xe6870030, - .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT), + .chcr = CHCR_TX(XMIT_SZ_16BIT), .mid_rid = 0xcd, }, { .slave_id = SHDMA_SLAVE_SDHI2_RX, .addr = 0xe6870030, - .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT), + .chcr = CHCR_RX(XMIT_SZ_16BIT), .mid_rid = 0xce, }, { .slave_id = SHDMA_SLAVE_FSIA_TX, .addr = 0xfe1f0024, - .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT), + .chcr = CHCR_TX(XMIT_SZ_32BIT), .mid_rid = 0xb1, }, { .slave_id = SHDMA_SLAVE_FSIA_RX, .addr = 0xfe1f0020, - .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT), + .chcr = CHCR_RX(XMIT_SZ_32BIT), .mid_rid = 0xb2, }, { .slave_id = SHDMA_SLAVE_MMCIF_TX, .addr = 0xe6bd0034, - .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT), + .chcr = CHCR_TX(XMIT_SZ_32BIT), .mid_rid = 0xd1, }, { .slave_id = SHDMA_SLAVE_MMCIF_RX, .addr = 0xe6bd0034, - .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT), + .chcr = CHCR_RX(XMIT_SZ_32BIT), .mid_rid = 0xd2, }, }; @@ -520,19 +496,17 @@ static const struct sh_dmae_channel sh7372_dmae_channels[] = { } }; -static const unsigned int ts_shift[] = TS_SHIFT; - static struct sh_dmae_pdata dma_platform_data = { .slave = sh7372_dmae_slaves, .slave_num = ARRAY_SIZE(sh7372_dmae_slaves), .channel = sh7372_dmae_channels, .channel_num = ARRAY_SIZE(sh7372_dmae_channels), - .ts_low_shift = 3, - .ts_low_mask = 0x18, - .ts_high_shift = (20 - 2), /* 2 bits for shifted low TS */ - .ts_high_mask = 0x00300000, - .ts_shift = ts_shift, - .ts_shift_num = ARRAY_SIZE(ts_shift), + .ts_low_shift = TS_LOW_SHIFT, + .ts_low_mask = TS_LOW_BIT << TS_LOW_SHIFT, + .ts_high_shift = TS_HI_SHIFT, + .ts_high_mask = TS_HI_BIT << TS_HI_SHIFT, + .ts_shift = dma_ts_shift, + .ts_shift_num = ARRAY_SIZE(dma_ts_shift), .dmaor_init = DMAOR_DME, .chclr_present = 1, }; @@ -654,17 +628,6 @@ static struct platform_device dma2_device = { /* * USB-DMAC */ - -unsigned int usbts_shift[] = {3, 4, 5}; - -enum { - XMIT_SZ_8BYTE = 0, - XMIT_SZ_16BYTE = 1, - XMIT_SZ_32BYTE = 2, -}; - -#define USBTS_INDEX2VAL(i) (((i) & 3) << 6) - static const struct sh_dmae_channel sh7372_usb_dmae_channels[] = { { .offset = 0, @@ -677,10 +640,10 @@ static const struct sh_dmae_channel sh7372_usb_dmae_channels[] = { static const struct sh_dmae_slave_config sh7372_usb_dmae0_slaves[] = { { .slave_id = SHDMA_SLAVE_USB0_TX, - .chcr = USBTS_INDEX2VAL(XMIT_SZ_8BYTE), + .chcr = USBTS_INDEX2VAL(USBTS_XMIT_SZ_8BYTE), }, { .slave_id = SHDMA_SLAVE_USB0_RX, - .chcr = USBTS_INDEX2VAL(XMIT_SZ_8BYTE), + .chcr = USBTS_INDEX2VAL(USBTS_XMIT_SZ_8BYTE), }, }; @@ -689,12 +652,12 @@ static struct sh_dmae_pdata usb_dma0_platform_data = { .slave_num = ARRAY_SIZE(sh7372_usb_dmae0_slaves), .channel = sh7372_usb_dmae_channels, .channel_num = ARRAY_SIZE(sh7372_usb_dmae_channels), - .ts_low_shift = 6, - .ts_low_mask = 0xc0, - .ts_high_shift = 0, - .ts_high_mask = 0, - .ts_shift = usbts_shift, - .ts_shift_num = ARRAY_SIZE(usbts_shift), + .ts_low_shift = USBTS_LOW_SHIFT, + .ts_low_mask = USBTS_LOW_BIT << USBTS_LOW_SHIFT, + .ts_high_shift = USBTS_HI_SHIFT, + .ts_high_mask = USBTS_HI_BIT << USBTS_HI_SHIFT, + .ts_shift = dma_usbts_shift, + .ts_shift_num = ARRAY_SIZE(dma_usbts_shift), .dmaor_init = DMAOR_DME, .chcr_offset = 0x14, .chcr_ie_bit = 1 << 5, @@ -739,10 +702,10 @@ static struct platform_device usb_dma0_device = { static const struct sh_dmae_slave_config sh7372_usb_dmae1_slaves[] = { { .slave_id = SHDMA_SLAVE_USB1_TX, - .chcr = USBTS_INDEX2VAL(XMIT_SZ_8BYTE), + .chcr = USBTS_INDEX2VAL(USBTS_XMIT_SZ_8BYTE), }, { .slave_id = SHDMA_SLAVE_USB1_RX, - .chcr = USBTS_INDEX2VAL(XMIT_SZ_8BYTE), + .chcr = USBTS_INDEX2VAL(USBTS_XMIT_SZ_8BYTE), }, }; @@ -751,12 +714,12 @@ static struct sh_dmae_pdata usb_dma1_platform_data = { .slave_num = ARRAY_SIZE(sh7372_usb_dmae1_slaves), .channel = sh7372_usb_dmae_channels, .channel_num = ARRAY_SIZE(sh7372_usb_dmae_channels), - .ts_low_shift = 6, - .ts_low_mask = 0xc0, - .ts_high_shift = 0, - .ts_high_mask = 0, - .ts_shift = usbts_shift, - .ts_shift_num = ARRAY_SIZE(usbts_shift), + .ts_low_shift = USBTS_LOW_SHIFT, + .ts_low_mask = USBTS_LOW_BIT << USBTS_LOW_SHIFT, + .ts_high_shift = USBTS_HI_SHIFT, + .ts_high_mask = USBTS_HI_BIT << USBTS_HI_SHIFT, + .ts_shift = dma_usbts_shift, + .ts_shift_num = ARRAY_SIZE(dma_usbts_shift), .dmaor_init = DMAOR_DME, .chcr_offset = 0x14, .chcr_ie_bit = 1 << 5, @@ -1038,21 +1001,21 @@ static struct platform_device *sh7372_late_devices[] __initdata = { void __init sh7372_add_standard_devices(void) { - sh7372_init_pm_domain(&sh7372_a4lc); - sh7372_init_pm_domain(&sh7372_a4mp); - sh7372_init_pm_domain(&sh7372_d4); - sh7372_init_pm_domain(&sh7372_a4r); - sh7372_init_pm_domain(&sh7372_a3rv); - sh7372_init_pm_domain(&sh7372_a3ri); - sh7372_init_pm_domain(&sh7372_a4s); - sh7372_init_pm_domain(&sh7372_a3sp); - sh7372_init_pm_domain(&sh7372_a3sg); - - sh7372_pm_add_subdomain(&sh7372_a4lc, &sh7372_a3rv); - sh7372_pm_add_subdomain(&sh7372_a4r, &sh7372_a4lc); - - sh7372_pm_add_subdomain(&sh7372_a4s, &sh7372_a3sg); - sh7372_pm_add_subdomain(&sh7372_a4s, &sh7372_a3sp); + rmobile_init_pm_domain(&sh7372_pd_a4lc); + rmobile_init_pm_domain(&sh7372_pd_a4mp); + rmobile_init_pm_domain(&sh7372_pd_d4); + rmobile_init_pm_domain(&sh7372_pd_a4r); + rmobile_init_pm_domain(&sh7372_pd_a3rv); + rmobile_init_pm_domain(&sh7372_pd_a3ri); + rmobile_init_pm_domain(&sh7372_pd_a4s); + rmobile_init_pm_domain(&sh7372_pd_a3sp); + rmobile_init_pm_domain(&sh7372_pd_a3sg); + + rmobile_pm_add_subdomain(&sh7372_pd_a4lc, &sh7372_pd_a3rv); + rmobile_pm_add_subdomain(&sh7372_pd_a4r, &sh7372_pd_a4lc); + + rmobile_pm_add_subdomain(&sh7372_pd_a4s, &sh7372_pd_a3sg); + rmobile_pm_add_subdomain(&sh7372_pd_a4s, &sh7372_pd_a3sp); platform_add_devices(sh7372_early_devices, ARRAY_SIZE(sh7372_early_devices)); @@ -1060,30 +1023,30 @@ void __init sh7372_add_standard_devices(void) platform_add_devices(sh7372_late_devices, ARRAY_SIZE(sh7372_late_devices)); - sh7372_add_device_to_domain(&sh7372_a3rv, &vpu_device); - sh7372_add_device_to_domain(&sh7372_a4mp, &spu0_device); - sh7372_add_device_to_domain(&sh7372_a4mp, &spu1_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &scif0_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &scif1_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &scif2_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &scif3_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &scif4_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &scif5_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &scif6_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &iic1_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &dma0_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &dma1_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &dma2_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &usb_dma0_device); - sh7372_add_device_to_domain(&sh7372_a3sp, &usb_dma1_device); - sh7372_add_device_to_domain(&sh7372_a4r, &iic0_device); - sh7372_add_device_to_domain(&sh7372_a4r, &veu0_device); - sh7372_add_device_to_domain(&sh7372_a4r, &veu1_device); - sh7372_add_device_to_domain(&sh7372_a4r, &veu2_device); - sh7372_add_device_to_domain(&sh7372_a4r, &veu3_device); - sh7372_add_device_to_domain(&sh7372_a4r, &jpu_device); - sh7372_add_device_to_domain(&sh7372_a4r, &tmu00_device); - sh7372_add_device_to_domain(&sh7372_a4r, &tmu01_device); + rmobile_add_device_to_domain(&sh7372_pd_a3rv, &vpu_device); + rmobile_add_device_to_domain(&sh7372_pd_a4mp, &spu0_device); + rmobile_add_device_to_domain(&sh7372_pd_a4mp, &spu1_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif0_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif1_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif2_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif3_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif4_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif5_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif6_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &iic1_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &dma0_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &dma1_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &dma2_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &usb_dma0_device); + rmobile_add_device_to_domain(&sh7372_pd_a3sp, &usb_dma1_device); + rmobile_add_device_to_domain(&sh7372_pd_a4r, &iic0_device); + rmobile_add_device_to_domain(&sh7372_pd_a4r, &veu0_device); + rmobile_add_device_to_domain(&sh7372_pd_a4r, &veu1_device); + rmobile_add_device_to_domain(&sh7372_pd_a4r, &veu2_device); + rmobile_add_device_to_domain(&sh7372_pd_a4r, &veu3_device); + rmobile_add_device_to_domain(&sh7372_pd_a4r, &jpu_device); + rmobile_add_device_to_domain(&sh7372_pd_a4r, &tmu00_device); + rmobile_add_device_to_domain(&sh7372_pd_a4r, &tmu01_device); } static void __init sh7372_earlytimer_init(void) diff --git a/arch/arm/mach-shmobile/setup-sh7377.c b/arch/arm/mach-shmobile/setup-sh7377.c index d576a6abbad..855b1506caf 100644 --- a/arch/arm/mach-shmobile/setup-sh7377.c +++ b/arch/arm/mach-shmobile/setup-sh7377.c @@ -22,6 +22,7 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/platform_device.h> +#include <linux/of_platform.h> #include <linux/uio_driver.h> #include <linux/delay.h> #include <linux/input.h> @@ -500,3 +501,49 @@ void __init sh7377_add_early_devices(void) /* override timer setup with soc-specific code */ shmobile_timer.init = sh7377_earlytimer_init; } + +#ifdef CONFIG_USE_OF + +void __init sh7377_add_early_devices_dt(void) +{ + shmobile_setup_delay(600, 1, 3); /* Cortex-A8 @ 600MHz */ + + early_platform_add_devices(sh7377_early_devices, + ARRAY_SIZE(sh7377_early_devices)); + + /* setup early console here as well */ + shmobile_setup_console(); +} + +static const struct of_dev_auxdata sh7377_auxdata_lookup[] __initconst = { + { } +}; + +void __init sh7377_add_standard_devices_dt(void) +{ + /* clocks are setup late during boot in the case of DT */ + sh7377_clock_init(); + + platform_add_devices(sh7377_early_devices, + ARRAY_SIZE(sh7377_early_devices)); + + of_platform_populate(NULL, of_default_bus_match_table, + sh7377_auxdata_lookup, NULL); +} + +static const char *sh7377_boards_compat_dt[] __initdata = { + "renesas,sh7377", + NULL, +}; + +DT_MACHINE_START(SH7377_DT, "Generic SH7377 (Flattened Device Tree)") + .map_io = sh7377_map_io, + .init_early = sh7377_add_early_devices_dt, + .init_irq = sh7377_init_irq, + .handle_irq = shmobile_handle_irq_intc, + .init_machine = sh7377_add_standard_devices_dt, + .timer = &shmobile_timer, + .dt_compat = sh7377_boards_compat_dt, +MACHINE_END + +#endif /* CONFIG_USE_OF */ diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c index 04a0dfe7549..d230af656fc 100644 --- a/arch/arm/mach-shmobile/setup-sh73a0.c +++ b/arch/arm/mach-shmobile/setup-sh73a0.c @@ -30,6 +30,7 @@ #include <linux/sh_dma.h> #include <linux/sh_intc.h> #include <linux/sh_timer.h> +#include <mach/dma-register.h> #include <mach/hardware.h> #include <mach/irqs.h> #include <mach/sh73a0.h> @@ -415,32 +416,6 @@ static struct platform_device i2c4_device = { .num_resources = ARRAY_SIZE(i2c4_resources), }; -/* Transmit sizes and respective CHCR register values */ -enum { - XMIT_SZ_8BIT = 0, - XMIT_SZ_16BIT = 1, - XMIT_SZ_32BIT = 2, - XMIT_SZ_64BIT = 7, - XMIT_SZ_128BIT = 3, - XMIT_SZ_256BIT = 4, - XMIT_SZ_512BIT = 5, -}; - -/* log2(size / 8) - used to calculate number of transfers */ -#define TS_SHIFT { \ - [XMIT_SZ_8BIT] = 0, \ - [XMIT_SZ_16BIT] = 1, \ - [XMIT_SZ_32BIT] = 2, \ - [XMIT_SZ_64BIT] = 3, \ - [XMIT_SZ_128BIT] = 4, \ - [XMIT_SZ_256BIT] = 5, \ - [XMIT_SZ_512BIT] = 6, \ -} - -#define TS_INDEX2VAL(i) ((((i) & 3) << 3) | (((i) & 0xc) << (20 - 2))) -#define CHCR_TX(xmit_sz) (DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL((xmit_sz))) -#define CHCR_RX(xmit_sz) (DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL((xmit_sz))) - static const struct sh_dmae_slave_config sh73a0_dmae_slaves[] = { { .slave_id = SHDMA_SLAVE_SCIF0_TX, @@ -604,19 +579,17 @@ static const struct sh_dmae_channel sh73a0_dmae_channels[] = { DMAE_CHANNEL(0x8980), }; -static const unsigned int ts_shift[] = TS_SHIFT; - static struct sh_dmae_pdata sh73a0_dmae_platform_data = { .slave = sh73a0_dmae_slaves, .slave_num = ARRAY_SIZE(sh73a0_dmae_slaves), .channel = sh73a0_dmae_channels, .channel_num = ARRAY_SIZE(sh73a0_dmae_channels), - .ts_low_shift = 3, - .ts_low_mask = 0x18, - .ts_high_shift = (20 - 2), /* 2 bits for shifted low TS */ - .ts_high_mask = 0x00300000, - .ts_shift = ts_shift, - .ts_shift_num = ARRAY_SIZE(ts_shift), + .ts_low_shift = TS_LOW_SHIFT, + .ts_low_mask = TS_LOW_BIT << TS_LOW_SHIFT, + .ts_high_shift = TS_HI_SHIFT, + .ts_high_mask = TS_HI_BIT << TS_HI_SHIFT, + .ts_shift = dma_ts_shift, + .ts_shift_num = ARRAY_SIZE(dma_ts_shift), .dmaor_init = DMAOR_DME, }; @@ -651,6 +624,116 @@ static struct platform_device dma0_device = { }, }; +/* MPDMAC */ +static const struct sh_dmae_slave_config sh73a0_mpdma_slaves[] = { + { + .slave_id = SHDMA_SLAVE_FSI2A_RX, + .addr = 0xec230020, + .chcr = CHCR_RX(XMIT_SZ_32BIT), + .mid_rid = 0xd6, /* CHECK ME */ + }, { + .slave_id = SHDMA_SLAVE_FSI2A_TX, + .addr = 0xec230024, + .chcr = CHCR_TX(XMIT_SZ_32BIT), + .mid_rid = 0xd5, /* CHECK ME */ + }, { + .slave_id = SHDMA_SLAVE_FSI2C_RX, + .addr = 0xec230060, + .chcr = CHCR_RX(XMIT_SZ_32BIT), + .mid_rid = 0xda, /* CHECK ME */ + }, { + .slave_id = SHDMA_SLAVE_FSI2C_TX, + .addr = 0xec230064, + .chcr = CHCR_TX(XMIT_SZ_32BIT), + .mid_rid = 0xd9, /* CHECK ME */ + }, { + .slave_id = SHDMA_SLAVE_FSI2B_RX, + .addr = 0xec240020, + .chcr = CHCR_RX(XMIT_SZ_32BIT), + .mid_rid = 0x8e, /* CHECK ME */ + }, { + .slave_id = SHDMA_SLAVE_FSI2B_TX, + .addr = 0xec240024, + .chcr = CHCR_RX(XMIT_SZ_32BIT), + .mid_rid = 0x8d, /* CHECK ME */ + }, { + .slave_id = SHDMA_SLAVE_FSI2D_RX, + .addr = 0xec240060, + .chcr = CHCR_RX(XMIT_SZ_32BIT), + .mid_rid = 0x9a, /* CHECK ME */ + }, +}; + +#define MPDMA_CHANNEL(a, b, c) \ +{ \ + .offset = a, \ + .dmars = b, \ + .dmars_bit = c, \ + .chclr_offset = (0x220 - 0x20) + a \ +} + +static const struct sh_dmae_channel sh73a0_mpdma_channels[] = { + MPDMA_CHANNEL(0x00, 0, 0), + MPDMA_CHANNEL(0x10, 0, 8), + MPDMA_CHANNEL(0x20, 4, 0), + MPDMA_CHANNEL(0x30, 4, 8), + MPDMA_CHANNEL(0x50, 8, 0), + MPDMA_CHANNEL(0x70, 8, 8), +}; + +static struct sh_dmae_pdata sh73a0_mpdma_platform_data = { + .slave = sh73a0_mpdma_slaves, + .slave_num = ARRAY_SIZE(sh73a0_mpdma_slaves), + .channel = sh73a0_mpdma_channels, + .channel_num = ARRAY_SIZE(sh73a0_mpdma_channels), + .ts_low_shift = TS_LOW_SHIFT, + .ts_low_mask = TS_LOW_BIT << TS_LOW_SHIFT, + .ts_high_shift = TS_HI_SHIFT, + .ts_high_mask = TS_HI_BIT << TS_HI_SHIFT, + .ts_shift = dma_ts_shift, + .ts_shift_num = ARRAY_SIZE(dma_ts_shift), + .dmaor_init = DMAOR_DME, + .chclr_present = 1, +}; + +/* Resource order important! */ +static struct resource sh73a0_mpdma_resources[] = { + { + /* Channel registers and DMAOR */ + .start = 0xec618020, + .end = 0xec61828f, + .flags = IORESOURCE_MEM, + }, + { + /* DMARSx */ + .start = 0xec619000, + .end = 0xec61900b, + .flags = IORESOURCE_MEM, + }, + { + .name = "error_irq", + .start = gic_spi(181), + .end = gic_spi(181), + .flags = IORESOURCE_IRQ, + }, + { + /* IRQ for channels 0-5 */ + .start = gic_spi(175), + .end = gic_spi(180), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device mpdma0_device = { + .name = "sh-dma-engine", + .id = 1, + .resource = sh73a0_mpdma_resources, + .num_resources = ARRAY_SIZE(sh73a0_mpdma_resources), + .dev = { + .platform_data = &sh73a0_mpdma_platform_data, + }, +}; + static struct platform_device *sh73a0_early_devices[] __initdata = { &scif0_device, &scif1_device, @@ -673,6 +756,7 @@ static struct platform_device *sh73a0_late_devices[] __initdata = { &i2c3_device, &i2c4_device, &dma0_device, + &mpdma0_device, }; #define SRCR2 0xe61580b0 diff --git a/arch/arm/mach-spear3xx/spear300.c b/arch/arm/mach-spear3xx/spear300.c index 0f882ecb7d8..6ec30054996 100644 --- a/arch/arm/mach-spear3xx/spear300.c +++ b/arch/arm/mach-spear3xx/spear300.c @@ -120,182 +120,156 @@ struct pl08x_channel_data spear300_dma_info[] = { .min_signal = 2, .max_signal = 2, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "uart0_tx", .min_signal = 3, .max_signal = 3, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ssp0_rx", .min_signal = 8, .max_signal = 8, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ssp0_tx", .min_signal = 9, .max_signal = 9, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "i2c_rx", .min_signal = 10, .max_signal = 10, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "i2c_tx", .min_signal = 11, .max_signal = 11, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "irda", .min_signal = 12, .max_signal = 12, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "adc", .min_signal = 13, .max_signal = 13, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "to_jpeg", .min_signal = 14, .max_signal = 14, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "from_jpeg", .min_signal = 15, .max_signal = 15, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras0_rx", .min_signal = 0, .max_signal = 0, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras0_tx", .min_signal = 1, .max_signal = 1, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras1_rx", .min_signal = 2, .max_signal = 2, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras1_tx", .min_signal = 3, .max_signal = 3, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras2_rx", .min_signal = 4, .max_signal = 4, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras2_tx", .min_signal = 5, .max_signal = 5, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras3_rx", .min_signal = 6, .max_signal = 6, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras3_tx", .min_signal = 7, .max_signal = 7, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras4_rx", .min_signal = 8, .max_signal = 8, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras4_tx", .min_signal = 9, .max_signal = 9, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras5_rx", .min_signal = 10, .max_signal = 10, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras5_tx", .min_signal = 11, .max_signal = 11, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras6_rx", .min_signal = 12, .max_signal = 12, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras6_tx", .min_signal = 13, .max_signal = 13, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras7_rx", .min_signal = 14, .max_signal = 14, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras7_tx", .min_signal = 15, .max_signal = 15, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, }; diff --git a/arch/arm/mach-spear3xx/spear310.c b/arch/arm/mach-spear3xx/spear310.c index bbcf4571d36..1d0e435b904 100644 --- a/arch/arm/mach-spear3xx/spear310.c +++ b/arch/arm/mach-spear3xx/spear310.c @@ -205,182 +205,156 @@ struct pl08x_channel_data spear310_dma_info[] = { .min_signal = 2, .max_signal = 2, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "uart0_tx", .min_signal = 3, .max_signal = 3, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ssp0_rx", .min_signal = 8, .max_signal = 8, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ssp0_tx", .min_signal = 9, .max_signal = 9, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "i2c_rx", .min_signal = 10, .max_signal = 10, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "i2c_tx", .min_signal = 11, .max_signal = 11, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "irda", .min_signal = 12, .max_signal = 12, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "adc", .min_signal = 13, .max_signal = 13, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "to_jpeg", .min_signal = 14, .max_signal = 14, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "from_jpeg", .min_signal = 15, .max_signal = 15, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "uart1_rx", .min_signal = 0, .max_signal = 0, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "uart1_tx", .min_signal = 1, .max_signal = 1, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "uart2_rx", .min_signal = 2, .max_signal = 2, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "uart2_tx", .min_signal = 3, .max_signal = 3, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "uart3_rx", .min_signal = 4, .max_signal = 4, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "uart3_tx", .min_signal = 5, .max_signal = 5, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "uart4_rx", .min_signal = 6, .max_signal = 6, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "uart4_tx", .min_signal = 7, .max_signal = 7, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "uart5_rx", .min_signal = 8, .max_signal = 8, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "uart5_tx", .min_signal = 9, .max_signal = 9, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras5_rx", .min_signal = 10, .max_signal = 10, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras5_tx", .min_signal = 11, .max_signal = 11, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras6_rx", .min_signal = 12, .max_signal = 12, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras6_tx", .min_signal = 13, .max_signal = 13, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras7_rx", .min_signal = 14, .max_signal = 14, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras7_tx", .min_signal = 15, .max_signal = 15, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, }; diff --git a/arch/arm/mach-spear3xx/spear320.c b/arch/arm/mach-spear3xx/spear320.c index 88d483bcd66..fd823c62457 100644 --- a/arch/arm/mach-spear3xx/spear320.c +++ b/arch/arm/mach-spear3xx/spear320.c @@ -213,182 +213,156 @@ struct pl08x_channel_data spear320_dma_info[] = { .min_signal = 2, .max_signal = 2, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "uart0_tx", .min_signal = 3, .max_signal = 3, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ssp0_rx", .min_signal = 8, .max_signal = 8, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ssp0_tx", .min_signal = 9, .max_signal = 9, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "i2c0_rx", .min_signal = 10, .max_signal = 10, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "i2c0_tx", .min_signal = 11, .max_signal = 11, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "irda", .min_signal = 12, .max_signal = 12, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "adc", .min_signal = 13, .max_signal = 13, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "to_jpeg", .min_signal = 14, .max_signal = 14, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "from_jpeg", .min_signal = 15, .max_signal = 15, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ssp1_rx", .min_signal = 0, .max_signal = 0, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "ssp1_tx", .min_signal = 1, .max_signal = 1, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "ssp2_rx", .min_signal = 2, .max_signal = 2, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "ssp2_tx", .min_signal = 3, .max_signal = 3, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "uart1_rx", .min_signal = 4, .max_signal = 4, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "uart1_tx", .min_signal = 5, .max_signal = 5, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "uart2_rx", .min_signal = 6, .max_signal = 6, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "uart2_tx", .min_signal = 7, .max_signal = 7, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "i2c1_rx", .min_signal = 8, .max_signal = 8, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "i2c1_tx", .min_signal = 9, .max_signal = 9, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "i2c2_rx", .min_signal = 10, .max_signal = 10, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "i2c2_tx", .min_signal = 11, .max_signal = 11, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "i2s_rx", .min_signal = 12, .max_signal = 12, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "i2s_tx", .min_signal = 13, .max_signal = 13, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "rs485_rx", .min_signal = 14, .max_signal = 14, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "rs485_tx", .min_signal = 15, .max_signal = 15, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB2, }, }; diff --git a/arch/arm/mach-spear3xx/spear3xx.c b/arch/arm/mach-spear3xx/spear3xx.c index 66db5f13af8..98144baf888 100644 --- a/arch/arm/mach-spear3xx/spear3xx.c +++ b/arch/arm/mach-spear3xx/spear3xx.c @@ -46,7 +46,8 @@ struct pl022_ssp_controller pl022_plat_data = { struct pl08x_platform_data pl080_plat_data = { .memcpy_channel = { .bus_id = "memcpy", - .cctl = (PL080_BSIZE_16 << PL080_CONTROL_SB_SIZE_SHIFT | \ + .cctl_memcpy = + (PL080_BSIZE_16 << PL080_CONTROL_SB_SIZE_SHIFT | \ PL080_BSIZE_16 << PL080_CONTROL_DB_SIZE_SHIFT | \ PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT | \ PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT | \ diff --git a/arch/arm/mach-spear6xx/spear6xx.c b/arch/arm/mach-spear6xx/spear6xx.c index 9af67d003c6..5a5a52db252 100644 --- a/arch/arm/mach-spear6xx/spear6xx.c +++ b/arch/arm/mach-spear6xx/spear6xx.c @@ -36,336 +36,288 @@ static struct pl08x_channel_data spear600_dma_info[] = { .min_signal = 0, .max_signal = 0, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ssp1_tx", .min_signal = 1, .max_signal = 1, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "uart0_rx", .min_signal = 2, .max_signal = 2, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "uart0_tx", .min_signal = 3, .max_signal = 3, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "uart1_rx", .min_signal = 4, .max_signal = 4, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "uart1_tx", .min_signal = 5, .max_signal = 5, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ssp2_rx", .min_signal = 6, .max_signal = 6, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "ssp2_tx", .min_signal = 7, .max_signal = 7, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "ssp0_rx", .min_signal = 8, .max_signal = 8, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ssp0_tx", .min_signal = 9, .max_signal = 9, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "i2c_rx", .min_signal = 10, .max_signal = 10, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "i2c_tx", .min_signal = 11, .max_signal = 11, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "irda", .min_signal = 12, .max_signal = 12, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "adc", .min_signal = 13, .max_signal = 13, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "to_jpeg", .min_signal = 14, .max_signal = 14, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "from_jpeg", .min_signal = 15, .max_signal = 15, .muxval = 0, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras0_rx", .min_signal = 0, .max_signal = 0, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras0_tx", .min_signal = 1, .max_signal = 1, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras1_rx", .min_signal = 2, .max_signal = 2, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras1_tx", .min_signal = 3, .max_signal = 3, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras2_rx", .min_signal = 4, .max_signal = 4, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras2_tx", .min_signal = 5, .max_signal = 5, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras3_rx", .min_signal = 6, .max_signal = 6, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras3_tx", .min_signal = 7, .max_signal = 7, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras4_rx", .min_signal = 8, .max_signal = 8, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras4_tx", .min_signal = 9, .max_signal = 9, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras5_rx", .min_signal = 10, .max_signal = 10, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras5_tx", .min_signal = 11, .max_signal = 11, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras6_rx", .min_signal = 12, .max_signal = 12, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras6_tx", .min_signal = 13, .max_signal = 13, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras7_rx", .min_signal = 14, .max_signal = 14, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ras7_tx", .min_signal = 15, .max_signal = 15, .muxval = 1, - .cctl = 0, .periph_buses = PL08X_AHB1, }, { .bus_id = "ext0_rx", .min_signal = 0, .max_signal = 0, .muxval = 2, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "ext0_tx", .min_signal = 1, .max_signal = 1, .muxval = 2, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "ext1_rx", .min_signal = 2, .max_signal = 2, .muxval = 2, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "ext1_tx", .min_signal = 3, .max_signal = 3, .muxval = 2, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "ext2_rx", .min_signal = 4, .max_signal = 4, .muxval = 2, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "ext2_tx", .min_signal = 5, .max_signal = 5, .muxval = 2, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "ext3_rx", .min_signal = 6, .max_signal = 6, .muxval = 2, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "ext3_tx", .min_signal = 7, .max_signal = 7, .muxval = 2, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "ext4_rx", .min_signal = 8, .max_signal = 8, .muxval = 2, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "ext4_tx", .min_signal = 9, .max_signal = 9, .muxval = 2, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "ext5_rx", .min_signal = 10, .max_signal = 10, .muxval = 2, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "ext5_tx", .min_signal = 11, .max_signal = 11, .muxval = 2, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "ext6_rx", .min_signal = 12, .max_signal = 12, .muxval = 2, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "ext6_tx", .min_signal = 13, .max_signal = 13, .muxval = 2, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "ext7_rx", .min_signal = 14, .max_signal = 14, .muxval = 2, - .cctl = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "ext7_tx", .min_signal = 15, .max_signal = 15, .muxval = 2, - .cctl = 0, .periph_buses = PL08X_AHB2, }, }; @@ -373,7 +325,8 @@ static struct pl08x_channel_data spear600_dma_info[] = { struct pl08x_platform_data pl080_plat_data = { .memcpy_channel = { .bus_id = "memcpy", - .cctl = (PL080_BSIZE_16 << PL080_CONTROL_SB_SIZE_SHIFT | \ + .cctl_memcpy = + (PL080_BSIZE_16 << PL080_CONTROL_SB_SIZE_SHIFT | \ PL080_BSIZE_16 << PL080_CONTROL_DB_SIZE_SHIFT | \ PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT | \ PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT | \ diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c index d0de9c1192f..c0999633a9a 100644 --- a/arch/arm/mach-tegra/board-dt-tegra20.c +++ b/arch/arm/mach-tegra/board-dt-tegra20.c @@ -64,7 +64,8 @@ struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { &tegra_ehci2_pdata), OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB3_BASE, "tegra-ehci.2", &tegra_ehci3_pdata), - OF_DEV_AUXDATA("nvidia,tegra20-apbdma", 0x6000a000, "tegra-apbdma", NULL), + OF_DEV_AUXDATA("nvidia,tegra20-apbdma", TEGRA_APB_DMA_BASE, "tegra-apbdma", NULL), + OF_DEV_AUXDATA("nvidia,tegra20-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL), {} }; diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c index ee48214bfd8..53bf60f1158 100644 --- a/arch/arm/mach-tegra/board-dt-tegra30.c +++ b/arch/arm/mach-tegra/board-dt-tegra30.c @@ -33,6 +33,8 @@ #include <asm/mach/arch.h> #include <asm/hardware/gic.h> +#include <mach/iomap.h> + #include "board.h" #include "clock.h" @@ -48,6 +50,7 @@ struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = { OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000D000, "tegra-i2c.4", NULL), OF_DEV_AUXDATA("nvidia,tegra30-ahub", 0x70080000, "tegra30-ahub", NULL), OF_DEV_AUXDATA("nvidia,tegra30-apbdma", 0x6000a000, "tegra-apbdma", NULL), + OF_DEV_AUXDATA("nvidia,tegra30-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL), {} }; diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index a310222951d..8674a890fd1 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -15,6 +15,7 @@ #include <linux/platform_device.h> #include <linux/io.h> #include <linux/i2c.h> +#include <linux/platform_data/i2c-nomadik.h> #include <linux/gpio.h> #include <linux/amba/bus.h> #include <linux/amba/pl022.h> @@ -40,7 +41,6 @@ #include <asm/mach/arch.h> #include <asm/hardware/gic.h> -#include <plat/i2c.h> #include <plat/ste_dma40.h> #include <plat/gpio-nomadik.h> @@ -211,24 +211,6 @@ static struct ab8500_platform_data ab8500_platdata = { .codec = &ab8500_codec_pdata, }; -static struct resource ab8500_resources[] = { - [0] = { - .start = IRQ_DB8500_AB8500, - .end = IRQ_DB8500_AB8500, - .flags = IORESOURCE_IRQ - } -}; - -struct platform_device ab8500_device = { - .name = "ab8500-core", - .id = 0, - .dev = { - .platform_data = &ab8500_platdata, - }, - .num_resources = 1, - .resource = ab8500_resources, -}; - /* * TPS61052 */ @@ -443,7 +425,6 @@ static struct hash_platform_data u8500_hash1_platform_data = { /* add any platform devices here - TODO */ static struct platform_device *mop500_platform_devs[] __initdata = { &mop500_gpio_keys_device, - &ab8500_device, }; #ifdef CONFIG_STE_DMA40 @@ -605,7 +586,6 @@ static struct platform_device *snowball_platform_devs[] __initdata = { &snowball_led_dev, &snowball_key_dev, &snowball_sbnet_dev, - &ab8500_device, }; static void __init mop500_init_machine(void) @@ -617,9 +597,8 @@ static void __init mop500_init_machine(void) mop500_gpio_keys[0].gpio = GPIO_PROX_SENSOR; mop500_pinmaps_init(); - parent = u8500_init_devices(); + parent = u8500_init_devices(&ab8500_platdata); - /* FIXME: parent of ab8500 should be prcmu */ for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++) mop500_platform_devs[i]->dev.parent = parent; @@ -652,7 +631,7 @@ static void __init snowball_init_machine(void) int i; snowball_pinmaps_init(); - parent = u8500_init_devices(); + parent = u8500_init_devices(&ab8500_platdata); for (i = 0; i < ARRAY_SIZE(snowball_platform_devs); i++) snowball_platform_devs[i]->dev.parent = parent; @@ -684,7 +663,7 @@ static void __init hrefv60_init_machine(void) mop500_gpio_keys[0].gpio = HREFV60_PROX_SENSE_GPIO; hrefv60_pinmaps_init(); - parent = u8500_init_devices(); + parent = u8500_init_devices(&ab8500_platdata); for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++) mop500_platform_devs[i]->dev.parent = parent; @@ -785,9 +764,6 @@ static const struct of_device_id u8500_local_bus_nodes[] = { /* only create devices below soc node */ { .compatible = "stericsson,db8500", }, { .compatible = "stericsson,db8500-prcmu", }, - { .compatible = "stericsson,db8500-prcmu-regulator", }, - { .compatible = "stericsson,ab8500", }, - { .compatible = "stericsson,ab8500-regulator", }, { .compatible = "simple-bus"}, { }, }; diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c index c8dd94f606d..db3c52d56ca 100644 --- a/arch/arm/mach-ux500/cpu-db8500.c +++ b/arch/arm/mach-ux500/cpu-db8500.c @@ -16,6 +16,7 @@ #include <linux/irq.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/mfd/abx500/ab8500.h> #include <asm/mach/map.h> #include <asm/pmu.h> @@ -115,7 +116,7 @@ static irqreturn_t db8500_pmu_handler(int irq, void *dev, irq_handler_t handler) return ret; } -static struct arm_pmu_platdata db8500_pmu_platdata = { +struct arm_pmu_platdata db8500_pmu_platdata = { .handle_irq = db8500_pmu_handler, }; @@ -206,7 +207,7 @@ static struct device * __init db8500_soc_device_init(void) /* * This function is called from the board init */ -struct device * __init u8500_init_devices(void) +struct device * __init u8500_init_devices(struct ab8500_platform_data *ab8500) { struct device *parent; int i; @@ -223,6 +224,8 @@ struct device * __init u8500_init_devices(void) for (i = 0; i < ARRAY_SIZE(platform_devs); i++) platform_devs[i]->dev.parent = parent; + db8500_prcmu_device.dev.platform_data = ab8500; + platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs)); return parent; diff --git a/arch/arm/mach-ux500/devices-common.h b/arch/arm/mach-ux500/devices-common.h index 6e470656026..ecdd8386cff 100644 --- a/arch/arm/mach-ux500/devices-common.h +++ b/arch/arm/mach-ux500/devices-common.h @@ -12,7 +12,7 @@ #include <linux/dma-mapping.h> #include <linux/sys_soc.h> #include <linux/amba/bus.h> -#include <plat/i2c.h> +#include <linux/platform_data/i2c-nomadik.h> #include <mach/crypto-ux500.h> struct spi_master_cntlr; @@ -56,27 +56,15 @@ dbx500_add_uart(struct device *parent, const char *name, resource_size_t base, struct nmk_i2c_controller; -static inline struct platform_device * +static inline struct amba_device * dbx500_add_i2c(struct device *parent, int id, resource_size_t base, int irq, struct nmk_i2c_controller *data) { - struct resource res[] = { - DEFINE_RES_MEM(base, SZ_4K), - DEFINE_RES_IRQ(irq), - }; + /* Conjure a name similar to what the platform device used to have */ + char name[16]; - struct platform_device_info pdevinfo = { - .parent = parent, - .name = "nmk-i2c", - .id = id, - .res = res, - .num_res = ARRAY_SIZE(res), - .data = data, - .size_data = sizeof(*data), - .dma_mask = DMA_BIT_MASK(32), - }; - - return platform_device_register_full(&pdevinfo); + snprintf(name, sizeof(name), "nmk-i2c.%d", id); + return amba_apb_device_add(parent, name, base, SZ_4K, irq, 0, data, 0); } static inline struct amba_device * diff --git a/arch/arm/mach-ux500/include/mach/setup.h b/arch/arm/mach-ux500/include/mach/setup.h index 8b7ed82a286..7914e5eaa9c 100644 --- a/arch/arm/mach-ux500/include/mach/setup.h +++ b/arch/arm/mach-ux500/include/mach/setup.h @@ -13,11 +13,12 @@ #include <asm/mach/time.h> #include <linux/init.h> +#include <linux/mfd/abx500/ab8500.h> void __init ux500_map_io(void); extern void __init u8500_map_io(void); -extern struct device * __init u8500_init_devices(void); +extern struct device * __init u8500_init_devices(struct ab8500_platform_data *ab8500); extern void __init ux500_init_irq(void); extern void __init ux500_init_late(void); diff --git a/arch/arm/mach-vt8500/Makefile b/arch/arm/mach-vt8500/Makefile index 54e69973f39..7ce51767c99 100644 --- a/arch/arm/mach-vt8500/Makefile +++ b/arch/arm/mach-vt8500/Makefile @@ -5,5 +5,3 @@ obj-$(CONFIG_VTWM_VERSION_WM8505) += devices-wm8505.o obj-$(CONFIG_MACH_BV07) += bv07.o obj-$(CONFIG_MACH_WM8505_7IN_NETBOOK) += wm8505_7in.o - -obj-$(CONFIG_HAVE_PWM) += pwm.o diff --git a/arch/arm/mach-vt8500/pwm.c b/arch/arm/mach-vt8500/pwm.c deleted file mode 100644 index 8ad825e9359..00000000000 --- a/arch/arm/mach-vt8500/pwm.c +++ /dev/null @@ -1,265 +0,0 @@ -/* - * arch/arm/mach-vt8500/pwm.c - * - * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/pwm.h> -#include <linux/delay.h> - -#include <asm/div64.h> - -#define VT8500_NR_PWMS 4 - -static DEFINE_MUTEX(pwm_lock); -static LIST_HEAD(pwm_list); - -struct pwm_device { - struct list_head node; - struct platform_device *pdev; - - const char *label; - - void __iomem *regbase; - - unsigned int use_count; - unsigned int pwm_id; -}; - -#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) -static inline void pwm_busy_wait(void __iomem *reg, u8 bitmask) -{ - int loops = msecs_to_loops(10); - while ((readb(reg) & bitmask) && --loops) - cpu_relax(); - - if (unlikely(!loops)) - pr_warning("Waiting for status bits 0x%x to clear timed out\n", - bitmask); -} - -int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) -{ - unsigned long long c; - unsigned long period_cycles, prescale, pv, dc; - - if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) - return -EINVAL; - - c = 25000000/2; /* wild guess --- need to implement clocks */ - c = c * period_ns; - do_div(c, 1000000000); - period_cycles = c; - - if (period_cycles < 1) - period_cycles = 1; - prescale = (period_cycles - 1) / 4096; - pv = period_cycles / (prescale + 1) - 1; - if (pv > 4095) - pv = 4095; - - if (prescale > 1023) - return -EINVAL; - - c = (unsigned long long)pv * duty_ns; - do_div(c, period_ns); - dc = c; - - pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 1)); - writel(prescale, pwm->regbase + 0x4 + (pwm->pwm_id << 4)); - - pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 2)); - writel(pv, pwm->regbase + 0x8 + (pwm->pwm_id << 4)); - - pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 3)); - writel(dc, pwm->regbase + 0xc + (pwm->pwm_id << 4)); - - return 0; -} -EXPORT_SYMBOL(pwm_config); - -int pwm_enable(struct pwm_device *pwm) -{ - pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 0)); - writel(5, pwm->regbase + (pwm->pwm_id << 4)); - return 0; -} -EXPORT_SYMBOL(pwm_enable); - -void pwm_disable(struct pwm_device *pwm) -{ - pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 0)); - writel(0, pwm->regbase + (pwm->pwm_id << 4)); -} -EXPORT_SYMBOL(pwm_disable); - -struct pwm_device *pwm_request(int pwm_id, const char *label) -{ - struct pwm_device *pwm; - int found = 0; - - mutex_lock(&pwm_lock); - - list_for_each_entry(pwm, &pwm_list, node) { - if (pwm->pwm_id == pwm_id) { - found = 1; - break; - } - } - - if (found) { - if (pwm->use_count == 0) { - pwm->use_count++; - pwm->label = label; - } else { - pwm = ERR_PTR(-EBUSY); - } - } else { - pwm = ERR_PTR(-ENOENT); - } - - mutex_unlock(&pwm_lock); - return pwm; -} -EXPORT_SYMBOL(pwm_request); - -void pwm_free(struct pwm_device *pwm) -{ - mutex_lock(&pwm_lock); - - if (pwm->use_count) { - pwm->use_count--; - pwm->label = NULL; - } else { - pr_warning("PWM device already freed\n"); - } - - mutex_unlock(&pwm_lock); -} -EXPORT_SYMBOL(pwm_free); - -static inline void __add_pwm(struct pwm_device *pwm) -{ - mutex_lock(&pwm_lock); - list_add_tail(&pwm->node, &pwm_list); - mutex_unlock(&pwm_lock); -} - -static int __devinit pwm_probe(struct platform_device *pdev) -{ - struct pwm_device *pwms; - struct resource *r; - int ret = 0; - int i; - - pwms = kzalloc(sizeof(struct pwm_device) * VT8500_NR_PWMS, GFP_KERNEL); - if (pwms == NULL) { - dev_err(&pdev->dev, "failed to allocate memory\n"); - return -ENOMEM; - } - - for (i = 0; i < VT8500_NR_PWMS; i++) { - pwms[i].use_count = 0; - pwms[i].pwm_id = i; - pwms[i].pdev = pdev; - } - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (r == NULL) { - dev_err(&pdev->dev, "no memory resource defined\n"); - ret = -ENODEV; - goto err_free; - } - - r = request_mem_region(r->start, resource_size(r), pdev->name); - if (r == NULL) { - dev_err(&pdev->dev, "failed to request memory resource\n"); - ret = -EBUSY; - goto err_free; - } - - pwms[0].regbase = ioremap(r->start, resource_size(r)); - if (pwms[0].regbase == NULL) { - dev_err(&pdev->dev, "failed to ioremap() registers\n"); - ret = -ENODEV; - goto err_free_mem; - } - - for (i = 1; i < VT8500_NR_PWMS; i++) - pwms[i].regbase = pwms[0].regbase; - - for (i = 0; i < VT8500_NR_PWMS; i++) - __add_pwm(&pwms[i]); - - platform_set_drvdata(pdev, pwms); - return 0; - -err_free_mem: - release_mem_region(r->start, resource_size(r)); -err_free: - kfree(pwms); - return ret; -} - -static int __devexit pwm_remove(struct platform_device *pdev) -{ - struct pwm_device *pwms; - struct resource *r; - int i; - - pwms = platform_get_drvdata(pdev); - if (pwms == NULL) - return -ENODEV; - - mutex_lock(&pwm_lock); - - for (i = 0; i < VT8500_NR_PWMS; i++) - list_del(&pwms[i].node); - mutex_unlock(&pwm_lock); - - iounmap(pwms[0].regbase); - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(r->start, resource_size(r)); - - kfree(pwms); - return 0; -} - -static struct platform_driver pwm_driver = { - .driver = { - .name = "vt8500-pwm", - .owner = THIS_MODULE, - }, - .probe = pwm_probe, - .remove = __devexit_p(pwm_remove), -}; - -static int __init pwm_init(void) -{ - return platform_driver_register(&pwm_driver); -} -arch_initcall(pwm_init); - -static void __exit pwm_exit(void) -{ - platform_driver_unregister(&pwm_driver); -} -module_exit(pwm_exit); - -MODULE_LICENSE("GPL"); diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 5cfc9899407..c2cdf6500f7 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -22,6 +22,7 @@ #include <linux/memblock.h> #include <linux/slab.h> #include <linux/iommu.h> +#include <linux/io.h> #include <linux/vmalloc.h> #include <linux/sizes.h> @@ -72,7 +73,7 @@ static dma_addr_t arm_dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir, struct dma_attrs *attrs) { - if (!arch_is_coherent()) + if (!arch_is_coherent() && !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs)) __dma_page_cpu_to_dev(page, offset, size, dir); return pfn_to_dma(dev, page_to_pfn(page)) + offset; } @@ -95,7 +96,7 @@ static void arm_dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir, struct dma_attrs *attrs) { - if (!arch_is_coherent()) + if (!arch_is_coherent() && !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs)) __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, handle)), handle & ~PAGE_MASK, size, dir); } @@ -124,6 +125,7 @@ struct dma_map_ops arm_dma_ops = { .alloc = arm_dma_alloc, .free = arm_dma_free, .mmap = arm_dma_mmap, + .get_sgtable = arm_dma_get_sgtable, .map_page = arm_dma_map_page, .unmap_page = arm_dma_unmap_page, .map_sg = arm_dma_map_sg, @@ -217,115 +219,70 @@ static void __dma_free_buffer(struct page *page, size_t size) } #ifdef CONFIG_MMU +#ifdef CONFIG_HUGETLB_PAGE +#error ARM Coherent DMA allocator does not (yet) support huge TLB +#endif -#define CONSISTENT_OFFSET(x) (((unsigned long)(x) - consistent_base) >> PAGE_SHIFT) -#define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - consistent_base) >> PMD_SHIFT) - -/* - * These are the page tables (2MB each) covering uncached, DMA consistent allocations - */ -static pte_t **consistent_pte; - -#define DEFAULT_CONSISTENT_DMA_SIZE SZ_2M +static void *__alloc_from_contiguous(struct device *dev, size_t size, + pgprot_t prot, struct page **ret_page); -static unsigned long consistent_base = CONSISTENT_END - DEFAULT_CONSISTENT_DMA_SIZE; +static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp, + pgprot_t prot, struct page **ret_page, + const void *caller); -void __init init_consistent_dma_size(unsigned long size) +static void * +__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot, + const void *caller) { - unsigned long base = CONSISTENT_END - ALIGN(size, SZ_2M); + struct vm_struct *area; + unsigned long addr; - BUG_ON(consistent_pte); /* Check we're called before DMA region init */ - BUG_ON(base < VMALLOC_END); + /* + * DMA allocation can be mapped to user space, so lets + * set VM_USERMAP flags too. + */ + area = get_vm_area_caller(size, VM_ARM_DMA_CONSISTENT | VM_USERMAP, + caller); + if (!area) + return NULL; + addr = (unsigned long)area->addr; + area->phys_addr = __pfn_to_phys(page_to_pfn(page)); - /* Grow region to accommodate specified size */ - if (base < consistent_base) - consistent_base = base; + if (ioremap_page_range(addr, addr + size, area->phys_addr, prot)) { + vunmap((void *)addr); + return NULL; + } + return (void *)addr; } -#include "vmregion.h" - -static struct arm_vmregion_head consistent_head = { - .vm_lock = __SPIN_LOCK_UNLOCKED(&consistent_head.vm_lock), - .vm_list = LIST_HEAD_INIT(consistent_head.vm_list), - .vm_end = CONSISTENT_END, -}; - -#ifdef CONFIG_HUGETLB_PAGE -#error ARM Coherent DMA allocator does not (yet) support huge TLB -#endif - -/* - * Initialise the consistent memory allocation. - */ -static int __init consistent_init(void) +static void __dma_free_remap(void *cpu_addr, size_t size) { - int ret = 0; - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - int i = 0; - unsigned long base = consistent_base; - unsigned long num_ptes = (CONSISTENT_END - base) >> PMD_SHIFT; - - if (IS_ENABLED(CONFIG_CMA) && !IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) - return 0; - - consistent_pte = kmalloc(num_ptes * sizeof(pte_t), GFP_KERNEL); - if (!consistent_pte) { - pr_err("%s: no memory\n", __func__); - return -ENOMEM; + unsigned int flags = VM_ARM_DMA_CONSISTENT | VM_USERMAP; + struct vm_struct *area = find_vm_area(cpu_addr); + if (!area || (area->flags & flags) != flags) { + WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr); + return; } - - pr_debug("DMA memory: 0x%08lx - 0x%08lx:\n", base, CONSISTENT_END); - consistent_head.vm_start = base; - - do { - pgd = pgd_offset(&init_mm, base); - - pud = pud_alloc(&init_mm, pgd, base); - if (!pud) { - pr_err("%s: no pud tables\n", __func__); - ret = -ENOMEM; - break; - } - - pmd = pmd_alloc(&init_mm, pud, base); - if (!pmd) { - pr_err("%s: no pmd tables\n", __func__); - ret = -ENOMEM; - break; - } - WARN_ON(!pmd_none(*pmd)); - - pte = pte_alloc_kernel(pmd, base); - if (!pte) { - pr_err("%s: no pte tables\n", __func__); - ret = -ENOMEM; - break; - } - - consistent_pte[i++] = pte; - base += PMD_SIZE; - } while (base < CONSISTENT_END); - - return ret; + unmap_kernel_range((unsigned long)cpu_addr, size); + vunmap(cpu_addr); } -core_initcall(consistent_init); -static void *__alloc_from_contiguous(struct device *dev, size_t size, - pgprot_t prot, struct page **ret_page); - -static struct arm_vmregion_head coherent_head = { - .vm_lock = __SPIN_LOCK_UNLOCKED(&coherent_head.vm_lock), - .vm_list = LIST_HEAD_INIT(coherent_head.vm_list), +struct dma_pool { + size_t size; + spinlock_t lock; + unsigned long *bitmap; + unsigned long nr_pages; + void *vaddr; + struct page *page; }; -static size_t coherent_pool_size = DEFAULT_CONSISTENT_DMA_SIZE / 8; +static struct dma_pool atomic_pool = { + .size = SZ_256K, +}; static int __init early_coherent_pool(char *p) { - coherent_pool_size = memparse(p, &p); + atomic_pool.size = memparse(p, &p); return 0; } early_param("coherent_pool", early_coherent_pool); @@ -333,32 +290,45 @@ early_param("coherent_pool", early_coherent_pool); /* * Initialise the coherent pool for atomic allocations. */ -static int __init coherent_init(void) +static int __init atomic_pool_init(void) { + struct dma_pool *pool = &atomic_pool; pgprot_t prot = pgprot_dmacoherent(pgprot_kernel); - size_t size = coherent_pool_size; + unsigned long nr_pages = pool->size >> PAGE_SHIFT; + unsigned long *bitmap; struct page *page; void *ptr; + int bitmap_size = BITS_TO_LONGS(nr_pages) * sizeof(long); - if (!IS_ENABLED(CONFIG_CMA)) - return 0; + bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!bitmap) + goto no_bitmap; - ptr = __alloc_from_contiguous(NULL, size, prot, &page); + if (IS_ENABLED(CONFIG_CMA)) + ptr = __alloc_from_contiguous(NULL, pool->size, prot, &page); + else + ptr = __alloc_remap_buffer(NULL, pool->size, GFP_KERNEL, prot, + &page, NULL); if (ptr) { - coherent_head.vm_start = (unsigned long) ptr; - coherent_head.vm_end = (unsigned long) ptr + size; - printk(KERN_INFO "DMA: preallocated %u KiB pool for atomic coherent allocations\n", - (unsigned)size / 1024); + spin_lock_init(&pool->lock); + pool->vaddr = ptr; + pool->page = page; + pool->bitmap = bitmap; + pool->nr_pages = nr_pages; + pr_info("DMA: preallocated %u KiB pool for atomic coherent allocations\n", + (unsigned)pool->size / 1024); return 0; } - printk(KERN_ERR "DMA: failed to allocate %u KiB pool for atomic coherent allocation\n", - (unsigned)size / 1024); + kfree(bitmap); +no_bitmap: + pr_err("DMA: failed to allocate %u KiB pool for atomic coherent allocation\n", + (unsigned)pool->size / 1024); return -ENOMEM; } /* * CMA is activated by core_initcall, so we must be called after it. */ -postcore_initcall(coherent_init); +postcore_initcall(atomic_pool_init); struct dma_contig_early_reserve { phys_addr_t base; @@ -406,112 +376,6 @@ void __init dma_contiguous_remap(void) } } -static void * -__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot, - const void *caller) -{ - struct arm_vmregion *c; - size_t align; - int bit; - - if (!consistent_pte) { - pr_err("%s: not initialised\n", __func__); - dump_stack(); - return NULL; - } - - /* - * Align the virtual region allocation - maximum alignment is - * a section size, minimum is a page size. This helps reduce - * fragmentation of the DMA space, and also prevents allocations - * smaller than a section from crossing a section boundary. - */ - bit = fls(size - 1); - if (bit > SECTION_SHIFT) - bit = SECTION_SHIFT; - align = 1 << bit; - - /* - * Allocate a virtual address in the consistent mapping region. - */ - c = arm_vmregion_alloc(&consistent_head, align, size, - gfp & ~(__GFP_DMA | __GFP_HIGHMEM), caller); - if (c) { - pte_t *pte; - int idx = CONSISTENT_PTE_INDEX(c->vm_start); - u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1); - - pte = consistent_pte[idx] + off; - c->priv = page; - - do { - BUG_ON(!pte_none(*pte)); - - set_pte_ext(pte, mk_pte(page, prot), 0); - page++; - pte++; - off++; - if (off >= PTRS_PER_PTE) { - off = 0; - pte = consistent_pte[++idx]; - } - } while (size -= PAGE_SIZE); - - dsb(); - - return (void *)c->vm_start; - } - return NULL; -} - -static void __dma_free_remap(void *cpu_addr, size_t size) -{ - struct arm_vmregion *c; - unsigned long addr; - pte_t *ptep; - int idx; - u32 off; - - c = arm_vmregion_find_remove(&consistent_head, (unsigned long)cpu_addr); - if (!c) { - pr_err("%s: trying to free invalid coherent area: %p\n", - __func__, cpu_addr); - dump_stack(); - return; - } - - if ((c->vm_end - c->vm_start) != size) { - pr_err("%s: freeing wrong coherent size (%ld != %d)\n", - __func__, c->vm_end - c->vm_start, size); - dump_stack(); - size = c->vm_end - c->vm_start; - } - - idx = CONSISTENT_PTE_INDEX(c->vm_start); - off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1); - ptep = consistent_pte[idx] + off; - addr = c->vm_start; - do { - pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep); - - ptep++; - addr += PAGE_SIZE; - off++; - if (off >= PTRS_PER_PTE) { - off = 0; - ptep = consistent_pte[++idx]; - } - - if (pte_none(pte) || !pte_present(pte)) - pr_crit("%s: bad page in kernel page table\n", - __func__); - } while (size -= PAGE_SIZE); - - flush_tlb_kernel_range(c->vm_start, c->vm_end); - - arm_vmregion_free(&consistent_head, c); -} - static int __dma_update_pte(pte_t *pte, pgtable_t token, unsigned long addr, void *data) { @@ -552,16 +416,17 @@ static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp, return ptr; } -static void *__alloc_from_pool(struct device *dev, size_t size, - struct page **ret_page, const void *caller) +static void *__alloc_from_pool(size_t size, struct page **ret_page) { - struct arm_vmregion *c; + struct dma_pool *pool = &atomic_pool; + unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; + unsigned int pageno; + unsigned long flags; + void *ptr = NULL; size_t align; - if (!coherent_head.vm_start) { - printk(KERN_ERR "%s: coherent pool not initialised!\n", - __func__); - dump_stack(); + if (!pool->vaddr) { + WARN(1, "coherent pool not initialised!\n"); return NULL; } @@ -571,35 +436,41 @@ static void *__alloc_from_pool(struct device *dev, size_t size, * size. This helps reduce fragmentation of the DMA space. */ align = PAGE_SIZE << get_order(size); - c = arm_vmregion_alloc(&coherent_head, align, size, 0, caller); - if (c) { - void *ptr = (void *)c->vm_start; - struct page *page = virt_to_page(ptr); - *ret_page = page; - return ptr; + + spin_lock_irqsave(&pool->lock, flags); + pageno = bitmap_find_next_zero_area(pool->bitmap, pool->nr_pages, + 0, count, (1 << align) - 1); + if (pageno < pool->nr_pages) { + bitmap_set(pool->bitmap, pageno, count); + ptr = pool->vaddr + PAGE_SIZE * pageno; + *ret_page = pool->page + pageno; } - return NULL; + spin_unlock_irqrestore(&pool->lock, flags); + + return ptr; } -static int __free_from_pool(void *cpu_addr, size_t size) +static int __free_from_pool(void *start, size_t size) { - unsigned long start = (unsigned long)cpu_addr; - unsigned long end = start + size; - struct arm_vmregion *c; + struct dma_pool *pool = &atomic_pool; + unsigned long pageno, count; + unsigned long flags; - if (start < coherent_head.vm_start || end > coherent_head.vm_end) + if (start < pool->vaddr || start > pool->vaddr + pool->size) return 0; - c = arm_vmregion_find_remove(&coherent_head, (unsigned long)start); - - if ((c->vm_end - c->vm_start) != size) { - printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n", - __func__, c->vm_end - c->vm_start, size); - dump_stack(); - size = c->vm_end - c->vm_start; + if (start + size > pool->vaddr + pool->size) { + WARN(1, "freeing wrong coherent size from pool\n"); + return 0; } - arm_vmregion_free(&coherent_head, c); + pageno = (start - pool->vaddr) >> PAGE_SHIFT; + count = size >> PAGE_SHIFT; + + spin_lock_irqsave(&pool->lock, flags); + bitmap_clear(pool->bitmap, pageno, count); + spin_unlock_irqrestore(&pool->lock, flags); + return 1; } @@ -644,7 +515,7 @@ static inline pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot) #define __get_dma_pgprot(attrs, prot) __pgprot(0) #define __alloc_remap_buffer(dev, size, gfp, prot, ret, c) NULL -#define __alloc_from_pool(dev, size, ret_page, c) NULL +#define __alloc_from_pool(size, ret_page) NULL #define __alloc_from_contiguous(dev, size, prot, ret) NULL #define __free_from_pool(cpu_addr, size) 0 #define __free_from_contiguous(dev, page, size) do { } while (0) @@ -702,10 +573,10 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, if (arch_is_coherent() || nommu()) addr = __alloc_simple_buffer(dev, size, gfp, &page); + else if (gfp & GFP_ATOMIC) + addr = __alloc_from_pool(size, &page); else if (!IS_ENABLED(CONFIG_CMA)) addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller); - else if (gfp & GFP_ATOMIC) - addr = __alloc_from_pool(dev, size, &page, caller); else addr = __alloc_from_contiguous(dev, size, prot, &page); @@ -741,16 +612,22 @@ int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma, { int ret = -ENXIO; #ifdef CONFIG_MMU + unsigned long nr_vma_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; unsigned long pfn = dma_to_pfn(dev, dma_addr); + unsigned long off = vma->vm_pgoff; + vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot); if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret)) return ret; - ret = remap_pfn_range(vma, vma->vm_start, - pfn + vma->vm_pgoff, - vma->vm_end - vma->vm_start, - vma->vm_page_prot); + if (off < nr_pages && nr_vma_pages <= (nr_pages - off)) { + ret = remap_pfn_range(vma, vma->vm_start, + pfn + off, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); + } #endif /* CONFIG_MMU */ return ret; @@ -785,6 +662,21 @@ void arm_dma_free(struct device *dev, size_t size, void *cpu_addr, } } +int arm_dma_get_sgtable(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t handle, size_t size, + struct dma_attrs *attrs) +{ + struct page *page = pfn_to_page(dma_to_pfn(dev, handle)); + int ret; + + ret = sg_alloc_table(sgt, 1, GFP_KERNEL); + if (unlikely(ret)) + return ret; + + sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0); + return 0; +} + static void dma_cache_maint_page(struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir, void (*op)(const void *, size_t, int)) @@ -998,9 +890,6 @@ static int arm_dma_set_mask(struct device *dev, u64 dma_mask) static int __init dma_debug_do_init(void) { -#ifdef CONFIG_MMU - arm_vmregion_create_proc("dma-mappings", &consistent_head); -#endif dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); return 0; } @@ -1088,7 +977,7 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t return pages; error: - while (--i) + while (i--) if (pages[i]) __free_pages(pages[i], 0); if (array_size <= PAGE_SIZE) @@ -1117,61 +1006,32 @@ static int __iommu_free_buffer(struct device *dev, struct page **pages, size_t s * Create a CPU mapping for a specified pages */ static void * -__iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot) +__iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot, + const void *caller) { - struct arm_vmregion *c; - size_t align; - size_t count = size >> PAGE_SHIFT; - int bit; + unsigned int i, nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; + struct vm_struct *area; + unsigned long p; - if (!consistent_pte[0]) { - pr_err("%s: not initialised\n", __func__); - dump_stack(); + area = get_vm_area_caller(size, VM_ARM_DMA_CONSISTENT | VM_USERMAP, + caller); + if (!area) return NULL; - } - - /* - * Align the virtual region allocation - maximum alignment is - * a section size, minimum is a page size. This helps reduce - * fragmentation of the DMA space, and also prevents allocations - * smaller than a section from crossing a section boundary. - */ - bit = fls(size - 1); - if (bit > SECTION_SHIFT) - bit = SECTION_SHIFT; - align = 1 << bit; - - /* - * Allocate a virtual address in the consistent mapping region. - */ - c = arm_vmregion_alloc(&consistent_head, align, size, - gfp & ~(__GFP_DMA | __GFP_HIGHMEM), NULL); - if (c) { - pte_t *pte; - int idx = CONSISTENT_PTE_INDEX(c->vm_start); - int i = 0; - u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1); - - pte = consistent_pte[idx] + off; - c->priv = pages; - - do { - BUG_ON(!pte_none(*pte)); - - set_pte_ext(pte, mk_pte(pages[i], prot), 0); - pte++; - off++; - i++; - if (off >= PTRS_PER_PTE) { - off = 0; - pte = consistent_pte[++idx]; - } - } while (i < count); - dsb(); + area->pages = pages; + area->nr_pages = nr_pages; + p = (unsigned long)area->addr; - return (void *)c->vm_start; + for (i = 0; i < nr_pages; i++) { + phys_addr_t phys = __pfn_to_phys(page_to_pfn(pages[i])); + if (ioremap_page_range(p, p + PAGE_SIZE, phys, prot)) + goto err; + p += PAGE_SIZE; } + return area->addr; +err: + unmap_kernel_range((unsigned long)area->addr, size); + vunmap(area->addr); return NULL; } @@ -1230,6 +1090,19 @@ static int __iommu_remove_mapping(struct device *dev, dma_addr_t iova, size_t si return 0; } +static struct page **__iommu_get_pages(void *cpu_addr, struct dma_attrs *attrs) +{ + struct vm_struct *area; + + if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) + return cpu_addr; + + area = find_vm_area(cpu_addr); + if (area && (area->flags & VM_ARM_DMA_CONSISTENT)) + return area->pages; + return NULL; +} + static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs) { @@ -1248,7 +1121,11 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, if (*handle == DMA_ERROR_CODE) goto err_buffer; - addr = __iommu_alloc_remap(pages, size, gfp, prot); + if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) + return pages; + + addr = __iommu_alloc_remap(pages, size, gfp, prot, + __builtin_return_address(0)); if (!addr) goto err_mapping; @@ -1265,31 +1142,25 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma, void *cpu_addr, dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs) { - struct arm_vmregion *c; + unsigned long uaddr = vma->vm_start; + unsigned long usize = vma->vm_end - vma->vm_start; + struct page **pages = __iommu_get_pages(cpu_addr, attrs); vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot); - c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr); - - if (c) { - struct page **pages = c->priv; - - unsigned long uaddr = vma->vm_start; - unsigned long usize = vma->vm_end - vma->vm_start; - int i = 0; - do { - int ret; + if (!pages) + return -ENXIO; - ret = vm_insert_page(vma, uaddr, pages[i++]); - if (ret) { - pr_err("Remapping memory, error: %d\n", ret); - return ret; - } + do { + int ret = vm_insert_page(vma, uaddr, *pages++); + if (ret) { + pr_err("Remapping memory failed: %d\n", ret); + return ret; + } + uaddr += PAGE_SIZE; + usize -= PAGE_SIZE; + } while (usize > 0); - uaddr += PAGE_SIZE; - usize -= PAGE_SIZE; - } while (usize > 0); - } return 0; } @@ -1300,16 +1171,35 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma, void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle, struct dma_attrs *attrs) { - struct arm_vmregion *c; + struct page **pages = __iommu_get_pages(cpu_addr, attrs); size = PAGE_ALIGN(size); - c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr); - if (c) { - struct page **pages = c->priv; - __dma_free_remap(cpu_addr, size); - __iommu_remove_mapping(dev, handle, size); - __iommu_free_buffer(dev, pages, size); + if (!pages) { + WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr); + return; } + + if (!dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) { + unmap_kernel_range((unsigned long)cpu_addr, size); + vunmap(cpu_addr); + } + + __iommu_remove_mapping(dev, handle, size); + __iommu_free_buffer(dev, pages, size); +} + +static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t dma_addr, + size_t size, struct dma_attrs *attrs) +{ + unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; + struct page **pages = __iommu_get_pages(cpu_addr, attrs); + + if (!pages) + return -ENXIO; + + return sg_alloc_table_from_pages(sgt, pages, count, 0, size, + GFP_KERNEL); } /* @@ -1317,7 +1207,7 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr, */ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg, size_t size, dma_addr_t *handle, - enum dma_data_direction dir) + enum dma_data_direction dir, struct dma_attrs *attrs) { struct dma_iommu_mapping *mapping = dev->archdata.mapping; dma_addr_t iova, iova_base; @@ -1336,7 +1226,8 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg, phys_addr_t phys = page_to_phys(sg_page(s)); unsigned int len = PAGE_ALIGN(s->offset + s->length); - if (!arch_is_coherent()) + if (!arch_is_coherent() && + !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs)) __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir); ret = iommu_map(mapping->domain, iova, phys, len, 0); @@ -1383,7 +1274,7 @@ int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents, if (s->offset || (size & ~PAGE_MASK) || size + s->length > max) { if (__map_sg_chunk(dev, start, size, &dma->dma_address, - dir) < 0) + dir, attrs) < 0) goto bad_mapping; dma->dma_address += offset; @@ -1396,7 +1287,7 @@ int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents, } size += s->length; } - if (__map_sg_chunk(dev, start, size, &dma->dma_address, dir) < 0) + if (__map_sg_chunk(dev, start, size, &dma->dma_address, dir, attrs) < 0) goto bad_mapping; dma->dma_address += offset; @@ -1430,7 +1321,8 @@ void arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, if (sg_dma_len(s)) __iommu_remove_mapping(dev, sg_dma_address(s), sg_dma_len(s)); - if (!arch_is_coherent()) + if (!arch_is_coherent() && + !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs)) __dma_page_dev_to_cpu(sg_page(s), s->offset, s->length, dir); } @@ -1492,7 +1384,7 @@ static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page, dma_addr_t dma_addr; int ret, len = PAGE_ALIGN(size + offset); - if (!arch_is_coherent()) + if (!arch_is_coherent() && !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs)) __dma_page_cpu_to_dev(page, offset, size, dir); dma_addr = __alloc_iova(mapping, len); @@ -1531,7 +1423,7 @@ static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle, if (!iova) return; - if (!arch_is_coherent()) + if (!arch_is_coherent() && !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs)) __dma_page_dev_to_cpu(page, offset, size, dir); iommu_unmap(mapping->domain, iova, len); @@ -1571,6 +1463,7 @@ struct dma_map_ops iommu_ops = { .alloc = arm_iommu_alloc_attrs, .free = arm_iommu_free_attrs, .mmap = arm_iommu_mmap_attrs, + .get_sgtable = arm_iommu_get_sgtable, .map_page = arm_iommu_map_page, .unmap_page = arm_iommu_unmap_page, diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h index 2e8a1efdf7b..6776160618e 100644 --- a/arch/arm/mm/mm.h +++ b/arch/arm/mm/mm.h @@ -59,6 +59,9 @@ extern void __flush_dcache_page(struct address_space *mapping, struct page *page #define VM_ARM_MTYPE(mt) ((mt) << 20) #define VM_ARM_MTYPE_MASK (0x1f << 20) +/* consistent regions used by dma_alloc_attrs() */ +#define VM_ARM_DMA_CONSISTENT 0x20000000 + #endif #ifdef CONFIG_ZONE_DMA diff --git a/arch/arm/mm/tlb-v7.S b/arch/arm/mm/tlb-v7.S index 845f461f8ec..c2021139cb5 100644 --- a/arch/arm/mm/tlb-v7.S +++ b/arch/arm/mm/tlb-v7.S @@ -38,11 +38,19 @@ ENTRY(v7wbi_flush_user_tlb_range) dsb mov r0, r0, lsr #PAGE_SHIFT @ align address mov r1, r1, lsr #PAGE_SHIFT +#ifdef CONFIG_ARM_ERRATA_720789 + mov r3, #0 +#else asid r3, r3 @ mask ASID +#endif orr r0, r3, r0, lsl #PAGE_SHIFT @ Create initial MVA mov r1, r1, lsl #PAGE_SHIFT 1: +#ifdef CONFIG_ARM_ERRATA_720789 + ALT_SMP(mcr p15, 0, r0, c8, c3, 3) @ TLB invalidate U MVA all ASID (shareable) +#else ALT_SMP(mcr p15, 0, r0, c8, c3, 1) @ TLB invalidate U MVA (shareable) +#endif ALT_UP(mcr p15, 0, r0, c8, c7, 1) @ TLB invalidate U MVA add r0, r0, #PAGE_SZ @@ -67,7 +75,11 @@ ENTRY(v7wbi_flush_kern_tlb_range) mov r0, r0, lsl #PAGE_SHIFT mov r1, r1, lsl #PAGE_SHIFT 1: +#ifdef CONFIG_ARM_ERRATA_720789 + ALT_SMP(mcr p15, 0, r0, c8, c3, 3) @ TLB invalidate U MVA all ASID (shareable) +#else ALT_SMP(mcr p15, 0, r0, c8, c3, 1) @ TLB invalidate U MVA (shareable) +#endif ALT_UP(mcr p15, 0, r0, c8, c7, 1) @ TLB invalidate U MVA add r0, r0, #PAGE_SZ cmp r0, r1 diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig index c722f9ce691..baf9064c084 100644 --- a/arch/arm/plat-mxc/Kconfig +++ b/arch/arm/plat-mxc/Kconfig @@ -47,12 +47,6 @@ config MXC_TZIC config MXC_AVIC bool -config MXC_PWM - tristate "Enable PWM driver" - select HAVE_PWM - help - Enable support for the i.MX PWM controller(s). - config MXC_DEBUG_BOARD bool "Enable MXC debug board(for 3-stack)" help diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile index 63b064b5c1d..6ac72003115 100644 --- a/arch/arm/plat-mxc/Makefile +++ b/arch/arm/plat-mxc/Makefile @@ -11,7 +11,6 @@ obj-$(CONFIG_MXC_AVIC) += avic.o obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o obj-$(CONFIG_IRAM_ALLOC) += iram_alloc.o -obj-$(CONFIG_MXC_PWM) += pwm.o obj-$(CONFIG_MXC_ULPI) += ulpi.o obj-$(CONFIG_MXC_USE_EPIT) += epit.o obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o diff --git a/arch/arm/plat-mxc/include/mach/i2c.h b/arch/arm/plat-mxc/include/mach/i2c.h index 375cdd0cf87..8289d915e61 100644 --- a/arch/arm/plat-mxc/include/mach/i2c.h +++ b/arch/arm/plat-mxc/include/mach/i2c.h @@ -15,7 +15,7 @@ * **/ struct imxi2c_platform_data { - int bitrate; + u32 bitrate; }; #endif /* __ASM_ARCH_I2C_H_ */ diff --git a/arch/arm/plat-mxc/pwm.c b/arch/arm/plat-mxc/pwm.c deleted file mode 100644 index c0cab2270dd..00000000000 --- a/arch/arm/plat-mxc/pwm.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * simple driver for PWM (Pulse Width Modulator) controller - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Derived from pxa PWM driver by eric miao <eric.miao@marvell.com> - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/err.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/pwm.h> -#include <mach/hardware.h> - - -/* i.MX1 and i.MX21 share the same PWM function block: */ - -#define MX1_PWMC 0x00 /* PWM Control Register */ -#define MX1_PWMS 0x04 /* PWM Sample Register */ -#define MX1_PWMP 0x08 /* PWM Period Register */ - - -/* i.MX27, i.MX31, i.MX35 share the same PWM function block: */ - -#define MX3_PWMCR 0x00 /* PWM Control Register */ -#define MX3_PWMSAR 0x0C /* PWM Sample Register */ -#define MX3_PWMPR 0x10 /* PWM Period Register */ -#define MX3_PWMCR_PRESCALER(x) (((x - 1) & 0xFFF) << 4) -#define MX3_PWMCR_DOZEEN (1 << 24) -#define MX3_PWMCR_WAITEN (1 << 23) -#define MX3_PWMCR_DBGEN (1 << 22) -#define MX3_PWMCR_CLKSRC_IPG_HIGH (2 << 16) -#define MX3_PWMCR_CLKSRC_IPG (1 << 16) -#define MX3_PWMCR_EN (1 << 0) - - - -struct pwm_device { - struct list_head node; - struct platform_device *pdev; - - const char *label; - struct clk *clk; - - int clk_enabled; - void __iomem *mmio_base; - - unsigned int use_count; - unsigned int pwm_id; -}; - -int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) -{ - if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) - return -EINVAL; - - if (!(cpu_is_mx1() || cpu_is_mx21())) { - unsigned long long c; - unsigned long period_cycles, duty_cycles, prescale; - u32 cr; - - c = clk_get_rate(pwm->clk); - c = c * period_ns; - do_div(c, 1000000000); - period_cycles = c; - - prescale = period_cycles / 0x10000 + 1; - - period_cycles /= prescale; - c = (unsigned long long)period_cycles * duty_ns; - do_div(c, period_ns); - duty_cycles = c; - - /* - * according to imx pwm RM, the real period value should be - * PERIOD value in PWMPR plus 2. - */ - if (period_cycles > 2) - period_cycles -= 2; - else - period_cycles = 0; - - writel(duty_cycles, pwm->mmio_base + MX3_PWMSAR); - writel(period_cycles, pwm->mmio_base + MX3_PWMPR); - - cr = MX3_PWMCR_PRESCALER(prescale) | - MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | - MX3_PWMCR_DBGEN | MX3_PWMCR_EN; - - if (cpu_is_mx25()) - cr |= MX3_PWMCR_CLKSRC_IPG; - else - cr |= MX3_PWMCR_CLKSRC_IPG_HIGH; - - writel(cr, pwm->mmio_base + MX3_PWMCR); - } else if (cpu_is_mx1() || cpu_is_mx21()) { - /* The PWM subsystem allows for exact frequencies. However, - * I cannot connect a scope on my device to the PWM line and - * thus cannot provide the program the PWM controller - * exactly. Instead, I'm relying on the fact that the - * Bootloader (u-boot or WinCE+haret) has programmed the PWM - * function group already. So I'll just modify the PWM sample - * register to follow the ratio of duty_ns vs. period_ns - * accordingly. - * - * This is good enough for programming the brightness of - * the LCD backlight. - * - * The real implementation would divide PERCLK[0] first by - * both the prescaler (/1 .. /128) and then by CLKSEL - * (/2 .. /16). - */ - u32 max = readl(pwm->mmio_base + MX1_PWMP); - u32 p = max * duty_ns / period_ns; - writel(max - p, pwm->mmio_base + MX1_PWMS); - } else { - BUG(); - } - - return 0; -} -EXPORT_SYMBOL(pwm_config); - -int pwm_enable(struct pwm_device *pwm) -{ - int rc = 0; - - if (!pwm->clk_enabled) { - rc = clk_prepare_enable(pwm->clk); - if (!rc) - pwm->clk_enabled = 1; - } - return rc; -} -EXPORT_SYMBOL(pwm_enable); - -void pwm_disable(struct pwm_device *pwm) -{ - writel(0, pwm->mmio_base + MX3_PWMCR); - - if (pwm->clk_enabled) { - clk_disable_unprepare(pwm->clk); - pwm->clk_enabled = 0; - } -} -EXPORT_SYMBOL(pwm_disable); - -static DEFINE_MUTEX(pwm_lock); -static LIST_HEAD(pwm_list); - -struct pwm_device *pwm_request(int pwm_id, const char *label) -{ - struct pwm_device *pwm; - int found = 0; - - mutex_lock(&pwm_lock); - - list_for_each_entry(pwm, &pwm_list, node) { - if (pwm->pwm_id == pwm_id) { - found = 1; - break; - } - } - - if (found) { - if (pwm->use_count == 0) { - pwm->use_count++; - pwm->label = label; - } else - pwm = ERR_PTR(-EBUSY); - } else - pwm = ERR_PTR(-ENOENT); - - mutex_unlock(&pwm_lock); - return pwm; -} -EXPORT_SYMBOL(pwm_request); - -void pwm_free(struct pwm_device *pwm) -{ - mutex_lock(&pwm_lock); - - if (pwm->use_count) { - pwm->use_count--; - pwm->label = NULL; - } else - pr_warning("PWM device already freed\n"); - - mutex_unlock(&pwm_lock); -} -EXPORT_SYMBOL(pwm_free); - -static int __devinit mxc_pwm_probe(struct platform_device *pdev) -{ - struct pwm_device *pwm; - struct resource *r; - int ret = 0; - - pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); - if (pwm == NULL) { - dev_err(&pdev->dev, "failed to allocate memory\n"); - return -ENOMEM; - } - - pwm->clk = clk_get(&pdev->dev, "pwm"); - - if (IS_ERR(pwm->clk)) { - ret = PTR_ERR(pwm->clk); - goto err_free; - } - - pwm->clk_enabled = 0; - - pwm->use_count = 0; - pwm->pwm_id = pdev->id; - pwm->pdev = pdev; - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (r == NULL) { - dev_err(&pdev->dev, "no memory resource defined\n"); - ret = -ENODEV; - goto err_free_clk; - } - - r = request_mem_region(r->start, resource_size(r), pdev->name); - if (r == NULL) { - dev_err(&pdev->dev, "failed to request memory resource\n"); - ret = -EBUSY; - goto err_free_clk; - } - - pwm->mmio_base = ioremap(r->start, resource_size(r)); - if (pwm->mmio_base == NULL) { - dev_err(&pdev->dev, "failed to ioremap() registers\n"); - ret = -ENODEV; - goto err_free_mem; - } - - mutex_lock(&pwm_lock); - list_add_tail(&pwm->node, &pwm_list); - mutex_unlock(&pwm_lock); - - platform_set_drvdata(pdev, pwm); - return 0; - -err_free_mem: - release_mem_region(r->start, resource_size(r)); -err_free_clk: - clk_put(pwm->clk); -err_free: - kfree(pwm); - return ret; -} - -static int __devexit mxc_pwm_remove(struct platform_device *pdev) -{ - struct pwm_device *pwm; - struct resource *r; - - pwm = platform_get_drvdata(pdev); - if (pwm == NULL) - return -ENODEV; - - mutex_lock(&pwm_lock); - list_del(&pwm->node); - mutex_unlock(&pwm_lock); - - iounmap(pwm->mmio_base); - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(r->start, resource_size(r)); - - clk_put(pwm->clk); - - kfree(pwm); - return 0; -} - -static struct platform_driver mxc_pwm_driver = { - .driver = { - .name = "mxc_pwm", - }, - .probe = mxc_pwm_probe, - .remove = __devexit_p(mxc_pwm_remove), -}; - -static int __init mxc_pwm_init(void) -{ - return platform_driver_register(&mxc_pwm_driver); -} -arch_initcall(mxc_pwm_init); - -static void __exit mxc_pwm_exit(void) -{ - platform_driver_unregister(&mxc_pwm_driver); -} -module_exit(mxc_pwm_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); diff --git a/arch/arm/plat-nomadik/include/plat/i2c.h b/arch/arm/plat-nomadik/include/plat/i2c.h deleted file mode 100644 index 8ba70ffc31e..00000000000 --- a/arch/arm/plat-nomadik/include/plat/i2c.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2009 ST-Ericsson - * - * 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. - */ -#ifndef __PLAT_I2C_H -#define __PLAT_I2C_H - -enum i2c_freq_mode { - I2C_FREQ_MODE_STANDARD, /* up to 100 Kb/s */ - I2C_FREQ_MODE_FAST, /* up to 400 Kb/s */ - I2C_FREQ_MODE_HIGH_SPEED, /* up to 3.4 Mb/s */ - I2C_FREQ_MODE_FAST_PLUS, /* up to 1 Mb/s */ -}; - -/** - * struct nmk_i2c_controller - client specific controller configuration - * @clk_freq: clock frequency for the operation mode - * @slsu: Slave data setup time in ns. - * The needed setup time for three modes of operation - * are 250ns, 100ns and 10ns respectively thus leading - * to the values of 14, 6, 2 for a 48 MHz i2c clk - * @tft: Tx FIFO Threshold in bytes - * @rft: Rx FIFO Threshold in bytes - * @timeout Slave response timeout(ms) - * @sm: speed mode - */ -struct nmk_i2c_controller { - unsigned long clk_freq; - unsigned short slsu; - unsigned char tft; - unsigned char rft; - int timeout; - enum i2c_freq_mode sm; -}; - -#endif /* __PLAT_I2C_H */ diff --git a/arch/arm/plat-omap/include/plat/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h index 5493bd95da5..eb3e4d55534 100644 --- a/arch/arm/plat-omap/include/plat/mmc.h +++ b/arch/arm/plat-omap/include/plat/mmc.h @@ -81,8 +81,6 @@ struct omap_mmc_platform_data { /* Return context loss count due to PM states changing */ int (*get_context_loss_count)(struct device *dev); - u64 dma_mask; - /* Integrating attributes from the omap_hwmod layer */ u8 controller_flags; diff --git a/arch/arm/plat-pxa/Makefile b/arch/arm/plat-pxa/Makefile index f302d048392..af8e484001e 100644 --- a/arch/arm/plat-pxa/Makefile +++ b/arch/arm/plat-pxa/Makefile @@ -8,5 +8,4 @@ obj-$(CONFIG_PXA3xx) += mfp.o obj-$(CONFIG_PXA95x) += mfp.o obj-$(CONFIG_ARCH_MMP) += mfp.o -obj-$(CONFIG_HAVE_PWM) += pwm.o obj-$(CONFIG_PXA_SSP) += ssp.o diff --git a/arch/arm/plat-pxa/pwm.c b/arch/arm/plat-pxa/pwm.c deleted file mode 100644 index ef32686feef..00000000000 --- a/arch/arm/plat-pxa/pwm.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - * linux/arch/arm/mach-pxa/pwm.c - * - * simple driver for PWM (Pulse Width Modulator) controller - * - * 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. - * - * 2008-02-13 initial version - * eric miao <eric.miao@marvell.com> - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/err.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/pwm.h> - -#include <asm/div64.h> - -#define HAS_SECONDARY_PWM 0x10 -#define PWM_ID_BASE(d) ((d) & 0xf) - -static const struct platform_device_id pwm_id_table[] = { - /* PWM has_secondary_pwm? */ - { "pxa25x-pwm", 0 }, - { "pxa27x-pwm", 0 | HAS_SECONDARY_PWM }, - { "pxa168-pwm", 1 }, - { "pxa910-pwm", 1 }, - { }, -}; -MODULE_DEVICE_TABLE(platform, pwm_id_table); - -/* PWM registers and bits definitions */ -#define PWMCR (0x00) -#define PWMDCR (0x04) -#define PWMPCR (0x08) - -#define PWMCR_SD (1 << 6) -#define PWMDCR_FD (1 << 10) - -struct pwm_device { - struct list_head node; - struct pwm_device *secondary; - struct platform_device *pdev; - - const char *label; - struct clk *clk; - int clk_enabled; - void __iomem *mmio_base; - - unsigned int use_count; - unsigned int pwm_id; -}; - -/* - * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE - * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE - */ -int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) -{ - unsigned long long c; - unsigned long period_cycles, prescale, pv, dc; - - if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) - return -EINVAL; - - c = clk_get_rate(pwm->clk); - c = c * period_ns; - do_div(c, 1000000000); - period_cycles = c; - - if (period_cycles < 1) - period_cycles = 1; - prescale = (period_cycles - 1) / 1024; - pv = period_cycles / (prescale + 1) - 1; - - if (prescale > 63) - return -EINVAL; - - if (duty_ns == period_ns) - dc = PWMDCR_FD; - else - dc = (pv + 1) * duty_ns / period_ns; - - /* NOTE: the clock to PWM has to be enabled first - * before writing to the registers - */ - clk_enable(pwm->clk); - __raw_writel(prescale, pwm->mmio_base + PWMCR); - __raw_writel(dc, pwm->mmio_base + PWMDCR); - __raw_writel(pv, pwm->mmio_base + PWMPCR); - clk_disable(pwm->clk); - - return 0; -} -EXPORT_SYMBOL(pwm_config); - -int pwm_enable(struct pwm_device *pwm) -{ - int rc = 0; - - if (!pwm->clk_enabled) { - rc = clk_enable(pwm->clk); - if (!rc) - pwm->clk_enabled = 1; - } - return rc; -} -EXPORT_SYMBOL(pwm_enable); - -void pwm_disable(struct pwm_device *pwm) -{ - if (pwm->clk_enabled) { - clk_disable(pwm->clk); - pwm->clk_enabled = 0; - } -} -EXPORT_SYMBOL(pwm_disable); - -static DEFINE_MUTEX(pwm_lock); -static LIST_HEAD(pwm_list); - -struct pwm_device *pwm_request(int pwm_id, const char *label) -{ - struct pwm_device *pwm; - int found = 0; - - mutex_lock(&pwm_lock); - - list_for_each_entry(pwm, &pwm_list, node) { - if (pwm->pwm_id == pwm_id) { - found = 1; - break; - } - } - - if (found) { - if (pwm->use_count == 0) { - pwm->use_count++; - pwm->label = label; - } else - pwm = ERR_PTR(-EBUSY); - } else - pwm = ERR_PTR(-ENOENT); - - mutex_unlock(&pwm_lock); - return pwm; -} -EXPORT_SYMBOL(pwm_request); - -void pwm_free(struct pwm_device *pwm) -{ - mutex_lock(&pwm_lock); - - if (pwm->use_count) { - pwm->use_count--; - pwm->label = NULL; - } else - pr_warning("PWM device already freed\n"); - - mutex_unlock(&pwm_lock); -} -EXPORT_SYMBOL(pwm_free); - -static inline void __add_pwm(struct pwm_device *pwm) -{ - mutex_lock(&pwm_lock); - list_add_tail(&pwm->node, &pwm_list); - mutex_unlock(&pwm_lock); -} - -static int __devinit pwm_probe(struct platform_device *pdev) -{ - const struct platform_device_id *id = platform_get_device_id(pdev); - struct pwm_device *pwm, *secondary = NULL; - struct resource *r; - int ret = 0; - - pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); - if (pwm == NULL) { - dev_err(&pdev->dev, "failed to allocate memory\n"); - return -ENOMEM; - } - - pwm->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(pwm->clk)) { - ret = PTR_ERR(pwm->clk); - goto err_free; - } - pwm->clk_enabled = 0; - - pwm->use_count = 0; - pwm->pwm_id = PWM_ID_BASE(id->driver_data) + pdev->id; - pwm->pdev = pdev; - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (r == NULL) { - dev_err(&pdev->dev, "no memory resource defined\n"); - ret = -ENODEV; - goto err_free_clk; - } - - r = request_mem_region(r->start, resource_size(r), pdev->name); - if (r == NULL) { - dev_err(&pdev->dev, "failed to request memory resource\n"); - ret = -EBUSY; - goto err_free_clk; - } - - pwm->mmio_base = ioremap(r->start, resource_size(r)); - if (pwm->mmio_base == NULL) { - dev_err(&pdev->dev, "failed to ioremap() registers\n"); - ret = -ENODEV; - goto err_free_mem; - } - - if (id->driver_data & HAS_SECONDARY_PWM) { - secondary = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); - if (secondary == NULL) { - ret = -ENOMEM; - goto err_free_mem; - } - - *secondary = *pwm; - pwm->secondary = secondary; - - /* registers for the second PWM has offset of 0x10 */ - secondary->mmio_base = pwm->mmio_base + 0x10; - secondary->pwm_id = pdev->id + 2; - } - - __add_pwm(pwm); - if (secondary) - __add_pwm(secondary); - - platform_set_drvdata(pdev, pwm); - return 0; - -err_free_mem: - release_mem_region(r->start, resource_size(r)); -err_free_clk: - clk_put(pwm->clk); -err_free: - kfree(pwm); - return ret; -} - -static int __devexit pwm_remove(struct platform_device *pdev) -{ - struct pwm_device *pwm; - struct resource *r; - - pwm = platform_get_drvdata(pdev); - if (pwm == NULL) - return -ENODEV; - - mutex_lock(&pwm_lock); - - if (pwm->secondary) { - list_del(&pwm->secondary->node); - kfree(pwm->secondary); - } - - list_del(&pwm->node); - mutex_unlock(&pwm_lock); - - iounmap(pwm->mmio_base); - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(r->start, resource_size(r)); - - clk_put(pwm->clk); - kfree(pwm); - return 0; -} - -static struct platform_driver pwm_driver = { - .driver = { - .name = "pxa25x-pwm", - .owner = THIS_MODULE, - }, - .probe = pwm_probe, - .remove = __devexit_p(pwm_remove), - .id_table = pwm_id_table, -}; - -static int __init pwm_init(void) -{ - return platform_driver_register(&pwm_driver); -} -arch_initcall(pwm_init); - -static void __exit pwm_exit(void) -{ - platform_driver_unregister(&pwm_driver); -} -module_exit(pwm_exit); - -MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile index b7871749667..9e40e8d0074 100644 --- a/arch/arm/plat-samsung/Makefile +++ b/arch/arm/plat-samsung/Makefile @@ -59,7 +59,3 @@ obj-$(CONFIG_SAMSUNG_WAKEMASK) += wakeup-mask.o obj-$(CONFIG_S5P_PM) += s5p-pm.o s5p-irq-pm.o obj-$(CONFIG_S5P_SLEEP) += s5p-sleep.o - -# PWM support - -obj-$(CONFIG_HAVE_PWM) += pwm.o diff --git a/arch/arm/plat-samsung/pwm.c b/arch/arm/plat-samsung/pwm.c deleted file mode 100644 index d3583050fb0..00000000000 --- a/arch/arm/plat-samsung/pwm.c +++ /dev/null @@ -1,416 +0,0 @@ -/* arch/arm/plat-s3c/pwm.c - * - * Copyright (c) 2007 Ben Dooks - * Copyright (c) 2008 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org> - * - * S3C series PWM device core - * - * 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. -*/ - -#include <linux/export.h> -#include <linux/kernel.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/err.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/pwm.h> - -#include <mach/map.h> - -#include <plat/regs-timer.h> - -struct pwm_device { - struct list_head list; - struct platform_device *pdev; - - struct clk *clk_div; - struct clk *clk; - const char *label; - - unsigned int period_ns; - unsigned int duty_ns; - - unsigned char tcon_base; - unsigned char use_count; - unsigned char pwm_id; -}; - -#define pwm_dbg(_pwm, msg...) dev_dbg(&(_pwm)->pdev->dev, msg) - -static struct clk *clk_scaler[2]; - -static inline int pwm_is_tdiv(struct pwm_device *pwm) -{ - return clk_get_parent(pwm->clk) == pwm->clk_div; -} - -static DEFINE_MUTEX(pwm_lock); -static LIST_HEAD(pwm_list); - -struct pwm_device *pwm_request(int pwm_id, const char *label) -{ - struct pwm_device *pwm; - int found = 0; - - mutex_lock(&pwm_lock); - - list_for_each_entry(pwm, &pwm_list, list) { - if (pwm->pwm_id == pwm_id) { - found = 1; - break; - } - } - - if (found) { - if (pwm->use_count == 0) { - pwm->use_count = 1; - pwm->label = label; - } else - pwm = ERR_PTR(-EBUSY); - } else - pwm = ERR_PTR(-ENOENT); - - mutex_unlock(&pwm_lock); - return pwm; -} - -EXPORT_SYMBOL(pwm_request); - - -void pwm_free(struct pwm_device *pwm) -{ - mutex_lock(&pwm_lock); - - if (pwm->use_count) { - pwm->use_count--; - pwm->label = NULL; - } else - printk(KERN_ERR "PWM%d device already freed\n", pwm->pwm_id); - - mutex_unlock(&pwm_lock); -} - -EXPORT_SYMBOL(pwm_free); - -#define pwm_tcon_start(pwm) (1 << (pwm->tcon_base + 0)) -#define pwm_tcon_invert(pwm) (1 << (pwm->tcon_base + 2)) -#define pwm_tcon_autoreload(pwm) (1 << (pwm->tcon_base + 3)) -#define pwm_tcon_manulupdate(pwm) (1 << (pwm->tcon_base + 1)) - -int pwm_enable(struct pwm_device *pwm) -{ - unsigned long flags; - unsigned long tcon; - - local_irq_save(flags); - - tcon = __raw_readl(S3C2410_TCON); - tcon |= pwm_tcon_start(pwm); - __raw_writel(tcon, S3C2410_TCON); - - local_irq_restore(flags); - - return 0; -} - -EXPORT_SYMBOL(pwm_enable); - -void pwm_disable(struct pwm_device *pwm) -{ - unsigned long flags; - unsigned long tcon; - - local_irq_save(flags); - - tcon = __raw_readl(S3C2410_TCON); - tcon &= ~pwm_tcon_start(pwm); - __raw_writel(tcon, S3C2410_TCON); - - local_irq_restore(flags); -} - -EXPORT_SYMBOL(pwm_disable); - -static unsigned long pwm_calc_tin(struct pwm_device *pwm, unsigned long freq) -{ - unsigned long tin_parent_rate; - unsigned int div; - - tin_parent_rate = clk_get_rate(clk_get_parent(pwm->clk_div)); - pwm_dbg(pwm, "tin parent at %lu\n", tin_parent_rate); - - for (div = 2; div <= 16; div *= 2) { - if ((tin_parent_rate / (div << 16)) < freq) - return tin_parent_rate / div; - } - - return tin_parent_rate / 16; -} - -#define NS_IN_HZ (1000000000UL) - -int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) -{ - unsigned long tin_rate; - unsigned long tin_ns; - unsigned long period; - unsigned long flags; - unsigned long tcon; - unsigned long tcnt; - long tcmp; - - /* We currently avoid using 64bit arithmetic by using the - * fact that anything faster than 1Hz is easily representable - * by 32bits. */ - - if (period_ns > NS_IN_HZ || duty_ns > NS_IN_HZ) - return -ERANGE; - - if (duty_ns > period_ns) - return -EINVAL; - - if (period_ns == pwm->period_ns && - duty_ns == pwm->duty_ns) - return 0; - - /* The TCMP and TCNT can be read without a lock, they're not - * shared between the timers. */ - - tcmp = __raw_readl(S3C2410_TCMPB(pwm->pwm_id)); - tcnt = __raw_readl(S3C2410_TCNTB(pwm->pwm_id)); - - period = NS_IN_HZ / period_ns; - - pwm_dbg(pwm, "duty_ns=%d, period_ns=%d (%lu)\n", - duty_ns, period_ns, period); - - /* Check to see if we are changing the clock rate of the PWM */ - - if (pwm->period_ns != period_ns) { - if (pwm_is_tdiv(pwm)) { - tin_rate = pwm_calc_tin(pwm, period); - clk_set_rate(pwm->clk_div, tin_rate); - } else - tin_rate = clk_get_rate(pwm->clk); - - pwm->period_ns = period_ns; - - pwm_dbg(pwm, "tin_rate=%lu\n", tin_rate); - - tin_ns = NS_IN_HZ / tin_rate; - tcnt = period_ns / tin_ns; - } else - tin_ns = NS_IN_HZ / clk_get_rate(pwm->clk); - - /* Note, counters count down */ - - tcmp = duty_ns / tin_ns; - tcmp = tcnt - tcmp; - /* the pwm hw only checks the compare register after a decrement, - so the pin never toggles if tcmp = tcnt */ - if (tcmp == tcnt) - tcmp--; - - pwm_dbg(pwm, "tin_ns=%lu, tcmp=%ld/%lu\n", tin_ns, tcmp, tcnt); - - if (tcmp < 0) - tcmp = 0; - - /* Update the PWM register block. */ - - local_irq_save(flags); - - __raw_writel(tcmp, S3C2410_TCMPB(pwm->pwm_id)); - __raw_writel(tcnt, S3C2410_TCNTB(pwm->pwm_id)); - - tcon = __raw_readl(S3C2410_TCON); - tcon |= pwm_tcon_manulupdate(pwm); - tcon |= pwm_tcon_autoreload(pwm); - __raw_writel(tcon, S3C2410_TCON); - - tcon &= ~pwm_tcon_manulupdate(pwm); - __raw_writel(tcon, S3C2410_TCON); - - local_irq_restore(flags); - - return 0; -} - -EXPORT_SYMBOL(pwm_config); - -static int pwm_register(struct pwm_device *pwm) -{ - pwm->duty_ns = -1; - pwm->period_ns = -1; - - mutex_lock(&pwm_lock); - list_add_tail(&pwm->list, &pwm_list); - mutex_unlock(&pwm_lock); - - return 0; -} - -static int s3c_pwm_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct pwm_device *pwm; - unsigned long flags; - unsigned long tcon; - unsigned int id = pdev->id; - int ret; - - if (id == 4) { - dev_err(dev, "TIMER4 is currently not supported\n"); - return -ENXIO; - } - - pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); - if (pwm == NULL) { - dev_err(dev, "failed to allocate pwm_device\n"); - return -ENOMEM; - } - - pwm->pdev = pdev; - pwm->pwm_id = id; - - /* calculate base of control bits in TCON */ - pwm->tcon_base = id == 0 ? 0 : (id * 4) + 4; - - pwm->clk = clk_get(dev, "pwm-tin"); - if (IS_ERR(pwm->clk)) { - dev_err(dev, "failed to get pwm tin clk\n"); - ret = PTR_ERR(pwm->clk); - goto err_alloc; - } - - pwm->clk_div = clk_get(dev, "pwm-tdiv"); - if (IS_ERR(pwm->clk_div)) { - dev_err(dev, "failed to get pwm tdiv clk\n"); - ret = PTR_ERR(pwm->clk_div); - goto err_clk_tin; - } - - clk_enable(pwm->clk); - clk_enable(pwm->clk_div); - - local_irq_save(flags); - - tcon = __raw_readl(S3C2410_TCON); - tcon |= pwm_tcon_invert(pwm); - __raw_writel(tcon, S3C2410_TCON); - - local_irq_restore(flags); - - - ret = pwm_register(pwm); - if (ret) { - dev_err(dev, "failed to register pwm\n"); - goto err_clk_tdiv; - } - - pwm_dbg(pwm, "config bits %02x\n", - (__raw_readl(S3C2410_TCON) >> pwm->tcon_base) & 0x0f); - - dev_info(dev, "tin at %lu, tdiv at %lu, tin=%sclk, base %d\n", - clk_get_rate(pwm->clk), - clk_get_rate(pwm->clk_div), - pwm_is_tdiv(pwm) ? "div" : "ext", pwm->tcon_base); - - platform_set_drvdata(pdev, pwm); - return 0; - - err_clk_tdiv: - clk_disable(pwm->clk_div); - clk_disable(pwm->clk); - clk_put(pwm->clk_div); - - err_clk_tin: - clk_put(pwm->clk); - - err_alloc: - kfree(pwm); - return ret; -} - -static int __devexit s3c_pwm_remove(struct platform_device *pdev) -{ - struct pwm_device *pwm = platform_get_drvdata(pdev); - - clk_disable(pwm->clk_div); - clk_disable(pwm->clk); - clk_put(pwm->clk_div); - clk_put(pwm->clk); - kfree(pwm); - - return 0; -} - -#ifdef CONFIG_PM -static int s3c_pwm_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct pwm_device *pwm = platform_get_drvdata(pdev); - - /* No one preserve these values during suspend so reset them - * Otherwise driver leaves PWM unconfigured if same values - * passed to pwm_config - */ - pwm->period_ns = 0; - pwm->duty_ns = 0; - - return 0; -} - -static int s3c_pwm_resume(struct platform_device *pdev) -{ - struct pwm_device *pwm = platform_get_drvdata(pdev); - unsigned long tcon; - - /* Restore invertion */ - tcon = __raw_readl(S3C2410_TCON); - tcon |= pwm_tcon_invert(pwm); - __raw_writel(tcon, S3C2410_TCON); - - return 0; -} - -#else -#define s3c_pwm_suspend NULL -#define s3c_pwm_resume NULL -#endif - -static struct platform_driver s3c_pwm_driver = { - .driver = { - .name = "s3c24xx-pwm", - .owner = THIS_MODULE, - }, - .probe = s3c_pwm_probe, - .remove = __devexit_p(s3c_pwm_remove), - .suspend = s3c_pwm_suspend, - .resume = s3c_pwm_resume, -}; - -static int __init pwm_init(void) -{ - int ret; - - clk_scaler[0] = clk_get(NULL, "pwm-scaler0"); - clk_scaler[1] = clk_get(NULL, "pwm-scaler1"); - - if (IS_ERR(clk_scaler[0]) || IS_ERR(clk_scaler[1])) { - printk(KERN_ERR "%s: failed to get scaler clocks\n", __func__); - return -EINVAL; - } - - ret = platform_driver_register(&s3c_pwm_driver); - if (ret) - printk(KERN_ERR "%s: failed to add pwm driver\n", __func__); - - return ret; -} - -arch_initcall(pwm_init); diff --git a/arch/arm/plat-spear/include/plat/pl080.h b/arch/arm/plat-spear/include/plat/pl080.h index 2bc6b54460a..eb6590ded40 100644 --- a/arch/arm/plat-spear/include/plat/pl080.h +++ b/arch/arm/plat-spear/include/plat/pl080.h @@ -14,8 +14,8 @@ #ifndef __PLAT_PL080_H #define __PLAT_PL080_H -struct pl08x_dma_chan; -int pl080_get_signal(struct pl08x_dma_chan *ch); -void pl080_put_signal(struct pl08x_dma_chan *ch); +struct pl08x_channel_data; +int pl080_get_signal(const struct pl08x_channel_data *cd); +void pl080_put_signal(const struct pl08x_channel_data *cd, int signal); #endif /* __PLAT_PL080_H */ diff --git a/arch/arm/plat-spear/pl080.c b/arch/arm/plat-spear/pl080.c index 12cf27f935f..cfa1199d0f4 100644 --- a/arch/arm/plat-spear/pl080.c +++ b/arch/arm/plat-spear/pl080.c @@ -27,9 +27,8 @@ struct { unsigned char val; } signals[16] = {{0, 0}, }; -int pl080_get_signal(struct pl08x_dma_chan *ch) +int pl080_get_signal(const struct pl08x_channel_data *cd) { - const struct pl08x_channel_data *cd = ch->cd; unsigned int signal = cd->min_signal, val; unsigned long flags; @@ -63,18 +62,17 @@ int pl080_get_signal(struct pl08x_dma_chan *ch) return signal; } -void pl080_put_signal(struct pl08x_dma_chan *ch) +void pl080_put_signal(const struct pl08x_channel_data *cd, int signal) { - const struct pl08x_channel_data *cd = ch->cd; unsigned long flags; spin_lock_irqsave(&lock, flags); /* if signal is not used */ - if (!signals[cd->min_signal].busy) + if (!signals[signal].busy) BUG(); - signals[cd->min_signal].busy--; + signals[signal].busy--; spin_unlock_irqrestore(&lock, flags); } diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S index 4fa9903b83c..cc926c98598 100644 --- a/arch/arm/vfp/entry.S +++ b/arch/arm/vfp/entry.S @@ -7,18 +7,20 @@ * 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. - * - * Basic entry code, called from the kernel's undefined instruction trap. - * r0 = faulted instruction - * r5 = faulted PC+4 - * r9 = successful return - * r10 = thread_info structure - * lr = failure return */ #include <asm/thread_info.h> #include <asm/vfpmacros.h> #include "../kernel/entry-header.S" +@ VFP entry point. +@ +@ r0 = instruction opcode (32-bit ARM or two 16-bit Thumb) +@ r2 = PC value to resume execution after successful emulation +@ r9 = normal "successful" return address +@ r10 = this threads thread_info structure +@ lr = unrecognised instruction return address +@ IRQs disabled. +@ ENTRY(do_vfp) #ifdef CONFIG_PREEMPT ldr r4, [r10, #TI_PREEMPT] @ get preempt count diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S index 2d30c7f6edd..ea0349f6358 100644 --- a/arch/arm/vfp/vfphw.S +++ b/arch/arm/vfp/vfphw.S @@ -16,6 +16,7 @@ */ #include <asm/thread_info.h> #include <asm/vfpmacros.h> +#include <linux/kern_levels.h> #include "../kernel/entry-header.S" .macro DBGSTR, str @@ -24,7 +25,7 @@ add r0, pc, #4 bl printk b 1f - .asciz "<7>VFP: \str\n" + .asciz KERN_DEBUG "VFP: \str\n" .balign 4 1: ldmfd sp!, {r0-r3, ip, lr} #endif @@ -37,7 +38,7 @@ add r0, pc, #4 bl printk b 1f - .asciz "<7>VFP: \str\n" + .asciz KERN_DEBUG "VFP: \str\n" .balign 4 1: ldmfd sp!, {r0-r3, ip, lr} #endif @@ -52,7 +53,7 @@ add r0, pc, #4 bl printk b 1f - .asciz "<7>VFP: \str\n" + .asciz KERN_DEBUG "VFP: \str\n" .balign 4 1: ldmfd sp!, {r0-r3, ip, lr} #endif @@ -61,13 +62,13 @@ @ VFP hardware support entry point. @ -@ r0 = faulted instruction -@ r2 = faulted PC+4 -@ r9 = successful return +@ r0 = instruction opcode (32-bit ARM or two 16-bit Thumb) +@ r2 = PC value to resume execution after successful emulation +@ r9 = normal "successful" return address @ r10 = vfp_state union @ r11 = CPU number -@ lr = failure return - +@ lr = unrecognised instruction return address +@ IRQs enabled. ENTRY(vfp_support_entry) DBGSTR3 "instr %08x pc %08x state %p", r0, r2, r10 @@ -161,9 +162,12 @@ vfp_hw_state_valid: @ exception before retrying branch @ out before setting an FPEXC that @ stops us reading stuff - VFPFMXR FPEXC, r1 @ restore FPEXC last - sub r2, r2, #4 - str r2, [sp, #S_PC] @ retry the instruction + VFPFMXR FPEXC, r1 @ Restore FPEXC last + sub r2, r2, #4 @ Retry current instruction - if Thumb + str r2, [sp, #S_PC] @ mode it's two 16-bit instructions, + @ else it's one 32-bit instruction, so + @ always subtract 4 from the following + @ instruction address. #ifdef CONFIG_PREEMPT get_thread_info r10 ldr r4, [r10, #TI_PREEMPT] @ get preempt count diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 586961929e9..fb849d044bd 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -457,10 +457,16 @@ static int vfp_pm_suspend(void) /* disable, just in case */ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); + } else if (vfp_current_hw_state[ti->cpu]) { +#ifndef CONFIG_SMP + fmxr(FPEXC, fpexc | FPEXC_EN); + vfp_save_state(vfp_current_hw_state[ti->cpu], fpexc); + fmxr(FPEXC, fpexc); +#endif } /* clear any information we had about last context state */ - memset(vfp_current_hw_state, 0, sizeof(vfp_current_hw_state)); + vfp_current_hw_state[ti->cpu] = NULL; return 0; } |