diff options
author | Zoltan HERPAI <wigyori@uid0.hu> | 2013-11-14 23:12:52 +0000 |
---|---|---|
committer | Zoltan HERPAI <wigyori@uid0.hu> | 2013-11-14 23:12:52 +0000 |
commit | 448a6b8d51f92ff19995645ff99f7f49804482fc (patch) | |
tree | 76658ab5db8672127f7cb73adb2682a83e432727 /target | |
parent | 4e381a077c60fb9518cc754c470094436f3f9c4d (diff) | |
download | upstream-448a6b8d51f92ff19995645ff99f7f49804482fc.tar.gz upstream-448a6b8d51f92ff19995645ff99f7f49804482fc.tar.bz2 upstream-448a6b8d51f92ff19995645ff99f7f49804482fc.zip |
sunxi: rework target
- update kernel to 3.12
- add patches for clocks, i2c, usb, sid, rtc
- support common image for A10/A13/A20
- add support for a couple boards
- most drivers are configured into the kernel as of now
Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@38811 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target')
48 files changed, 4313 insertions, 175 deletions
diff --git a/target/linux/sunxi/Makefile b/target/linux/sunxi/Makefile index e60f550360..658de40028 100644 --- a/target/linux/sunxi/Makefile +++ b/target/linux/sunxi/Makefile @@ -4,19 +4,26 @@ # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. # + include $(TOPDIR)/rules.mk ARCH:=arm BOARD:=sunxi -BOARDNAME:=Allwinner SoC -FEATURES:=targz -SUBTARGETS=cortex-a7 cortex-a8 -MAINTAINER:=Luka Perkov <luka@openwrt.org> +BOARDNAME:=Allwinner A1x/A20/A3x +FEATURES:=fpu usb ext4 display +CPU_TYPE:=cortex-a8 +CPU_SUBTYPE:=vfpv3 +MAINTAINER:=Zoltan HERPAI <wigyori@uid0.hu> -LINUX_VERSION:=3.10.18 +LINUX_VERSION:=3.12 +KERNELNAME:="zImage dtbs" +DEFAULT_PACKAGES += uboot-envtools uboot-sunxi -include $(INCLUDE_DIR)/target.mk +# A10: Cortex-A8 +# A13: Cortex-A8 +# A20: dual Cortex-A7 +# A31: quad Cortex-A7 -KERNELNAME:="zImage dtbs" +include $(INCLUDE_DIR)/target.mk $(eval $(call BuildTarget)) diff --git a/target/linux/sunxi/base-files/etc/inittab b/target/linux/sunxi/base-files/etc/inittab new file mode 100644 index 0000000000..e9de30bcc4 --- /dev/null +++ b/target/linux/sunxi/base-files/etc/inittab @@ -0,0 +1,5 @@ +::sysinit:/etc/init.d/rcS S boot +::shutdown:/etc/init.d/rcS K shutdown +tts/0::askfirst:/bin/ash --login +ttyS0::askfirst:/bin/ash --login +tty1::askfirst:/bin/ash --login diff --git a/target/linux/sunxi/base-files/lib/preinit/01_preinit_sunxi.sh b/target/linux/sunxi/base-files/lib/preinit/01_preinit_sunxi.sh new file mode 100644 index 0000000000..f221dbc582 --- /dev/null +++ b/target/linux/sunxi/base-files/lib/preinit/01_preinit_sunxi.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +do_sunxi() { + . /lib/sunxi.sh + + sunxi_board_detect +} + +boot_hook_add preinit_main do_sunxi diff --git a/target/linux/sunxi/base-files/lib/sunxi.sh b/target/linux/sunxi/base-files/lib/sunxi.sh new file mode 100644 index 0000000000..adf9f8462c --- /dev/null +++ b/target/linux/sunxi/base-files/lib/sunxi.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +# defaults +SUNXI_BOARD_NAME="generic sunxi" +SUNXI_BOARD_MODEL="generic sunxi" +SUNXI_ENV_DEV=/dev/mmcblk0 + +#Helper functions +get_cmdline_opt() +{ +cat /proc/cmdline | awk -F$1= '{print $2}' | awk '{print $1}' +} + +#Since fw_getenv doesn't work with blockdevs let's make a hack +uboot_getenv() +{ + dd if=$SUNXI_ENV_DEV bs=1024 skip=544 count=128 2>dev/null |\strings|grep $1|cut -d"=" -f2 +} + +#Actual routines go below +sunxi_env_dev() +{ + local dev + dev=`get_cmdline_opt root|cut -d"p" -f1` + SUNXI_ENV_DEV=$dev + echo "probing $dev for uboot env data" +} + +sunxi_board_detect() { + local board + local model + sunxi_env_dev + [ -e "/tmp/sysinfo/" ] || mkdir -p "/tmp/sysinfo/" + board="`uboot_getenv wrt_board`" + model="`uboot_getenv wrt_model`" + if [ "$board" != "" ]; then + SUNXI_BOARD_NAME="$board" + fi + if [ "$model" != "" ]; then + SUNXI_BOARD_MODEL="$model" + fi + echo "$SUNXI_BOARD_NAME" > /tmp/sysinfo/board_name + echo "$SUNXI_BOARD_MODEL" > /tmp/sysinfo/model + echo "Detected $SUNXI_BOARD_NAME // $SUNXI_BOARD_MODEL" +} diff --git a/target/linux/sunxi/config-3.12 b/target/linux/sunxi/config-3.12 new file mode 100644 index 0000000000..4a3bc4ab85 --- /dev/null +++ b/target/linux/sunxi/config-3.12 @@ -0,0 +1,434 @@ +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_APM_EMULATION is not set +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y +CONFIG_ARCH_HAS_RESET_CONTROLLER=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_MULTIPLATFORM=y +# CONFIG_ARCH_MULTI_CPU_AUTO is not set +CONFIG_ARCH_MULTI_V6_V7=y +CONFIG_ARCH_MULTI_V7=y +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set +CONFIG_ARCH_NR_GPIO=288 +CONFIG_ARCH_REQUIRE_GPIOLIB=y +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +CONFIG_ARCH_SUNXI=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_ARM=y +CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ATAG_DTB_COMPAT=y +# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND is not set +CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER=y +# CONFIG_ARM_CPU_SUSPEND is not set +CONFIG_ARM_ERRATA_430973=y +CONFIG_ARM_ERRATA_720789=y +CONFIG_ARM_ERRATA_754322=y +CONFIG_ARM_ERRATA_775420=y +CONFIG_ARM_GIC=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_L1_CACHE_SHIFT_6=y +# CONFIG_ARM_LPAE is not set +CONFIG_ARM_NR_BANKS=8 +CONFIG_ARM_PATCH_PHYS_VIRT=y +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_ARM_VIRT_EXT=y +CONFIG_ATA=y +CONFIG_ATAGS=y +CONFIG_AUDIT=y +# CONFIG_AUDITSYSCALL is not set +CONFIG_AUDIT_GENERIC=y +CONFIG_AUTO_ZRELADDR=y +CONFIG_AVERAGE=y +CONFIG_BINFMT_MISC=y +CONFIG_BLK_CGROUP=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_BOUNCE=y +CONFIG_BRIDGE_IGMP_SNOOPING=y +# CONFIG_CACHE_L2X0 is not set +CONFIG_CFG80211=y +# CONFIG_CFG80211_DEBUGFS is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_INTERNAL_REGDB is not set +# CONFIG_CFG80211_REG_DEBUG is not set +# CONFIG_CFG80211_WEXT is not set +CONFIG_CFQ_GROUP_IOSCHED=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_FREEZER=y +# CONFIG_CGROUP_PERF is not set +# CONFIG_CGROUP_SCHED is not set +# CONFIG_CHARGER_BQ24190 is not set +# CONFIG_CHARGER_MANAGER is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLKSRC_OF=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CMDLINE="console=ttyS0,115200 earlyprintk" +CONFIG_CMDLINE_FORCE=y +CONFIG_COMMON_CLK=y +CONFIG_COMPACTION=y +CONFIG_CONFIGFS_FS=y +CONFIG_CONNECTOR=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_COREDUMP=y +CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y +CONFIG_CPUSETS=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_HAS_ASID=y +# CONFIG_CPU_ICACHE_DISABLE is not set +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_RMAP=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_V7=y +CONFIG_CRC_T10DIF=y +CONFIG_CRYPTO_ARC4=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_CRCT10DIF=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_DEBUG_BLK_CGROUP is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_KERNEL is not set +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +CONFIG_DEBUG_MEMORY_INIT=y +# CONFIG_DEBUG_UART_8250 is not set +# CONFIG_DEBUG_UART_PL01X is not set +# CONFIG_DEBUG_USER is not set +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_LZO=y +CONFIG_DECOMPRESS_XZ=y +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_DIRECT_IO=y +CONFIG_DMADEVICES=y +CONFIG_DMA_OF=y +CONFIG_DNOTIFY=y +CONFIG_DTC=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_DW_DMAC_CORE is not set +CONFIG_DYNAMIC_DEBUG=y +CONFIG_EEPROM_SUNXI_SID=y +CONFIG_ELF_CORE=y +# CONFIG_EMBEDDED is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_EXPERT is not set +CONFIG_FRAME_POINTER=y +CONFIG_FRAME_WARN=2048 +CONFIG_FREEZER=y +CONFIG_FS_POSIX_ACL=y +CONFIG_GARP=y +CONFIG_GENERIC_ACL=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IO=y +CONFIG_GENERIC_IRQ_CHIP=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_DEVRES=y +# CONFIG_HAMRADIO is not set +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_HAVE_BPF_JIT=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_HAVE_DEBUG_KMEMLEAK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_NET_DSA=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_SMP=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_UID16=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_CONSOLE=y +CONFIG_HZ_FIXED=0 +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_MUX=y +# CONFIG_I2C_MUX_GPIO is not set +# CONFIG_I2C_MUX_PCA9541 is not set +# CONFIG_I2C_MUX_PCA954x is not set +CONFIG_I2C_MUX_PINCTRL=y +CONFIG_I2C_MV64XXX=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INPUT=y +# CONFIG_INPUT_MISC is not set +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_IOSCHED_CFQ=y +CONFIG_IPC_NS=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_BOOTP is not set +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_RARP is not set +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +CONFIG_KALLSYMS=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_XZ is not set +CONFIG_KSM=y +CONFIG_KTIME_SCALAR=y +# CONFIG_LBDAF is not set +CONFIG_LEDS_GPIO=y +# CONFIG_LEDS_REGULATOR is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LOG_BUF_SHIFT=19 +CONFIG_LZ4_DECOMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_MAC80211=y +# CONFIG_MAC80211_DEBUGFS is not set +# CONFIG_MAC80211_DEBUG_MENU is not set +CONFIG_MAC80211_HAS_RC=y +# CONFIG_MAC80211_HWSIM is not set +# CONFIG_MAC80211_LEDS is not set +# CONFIG_MAC80211_MESH is not set +CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" +CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y +CONFIG_MAC80211_RC_MINSTREL=y +CONFIG_MAC80211_RC_MINSTREL_HT=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MDIO_BOARDINFO=y +CONFIG_MDIO_SUN4I=y +# CONFIG_MEMCG is not set +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_BLOCK=y +# CONFIG_MMC_BLOCK_BOUNCE is not set +CONFIG_MMC_DW=y +# CONFIG_MMC_DW_EXYNOS is not set +# CONFIG_MMC_DW_IDMAC is not set +CONFIG_MMC_DW_PLTFM=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MODULES_USE_ELF_REL=y +# CONFIG_MTD is not set +CONFIG_MULTI_IRQ_HANDLER=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +# CONFIG_MWIFIEX is not set +CONFIG_NAMESPACES=y +CONFIG_NEED_DMA_MAP_STATE=y +# CONFIG_NEON is not set +# CONFIG_NETPRIO_CGROUP is not set +# CONFIG_NET_CLS_CGROUP is not set +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_NS=y +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_NET_VENDOR_ALLWINNER=y +# CONFIG_NL80211_TESTMODE is not set +CONFIG_NLS=y +CONFIG_NO_HZ=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +CONFIG_NR_CPUS=4 +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_MDIO=y +CONFIG_OF_NET=y +CONFIG_OLD_SIGACTION=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_PAGE_OFFSET=0xC0000000 +# CONFIG_PARTITION_ADVANCED is not set +# CONFIG_PCI_SYSCALL is not set +CONFIG_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PHYLIB=y +CONFIG_PID_NS=y +CONFIG_PINCTRL=y +# CONFIG_PINCTRL_SINGLE is not set +CONFIG_PINCTRL_SUNXI=y +CONFIG_PM=y +CONFIG_PM_CLK=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_RUNTIME=y +CONFIG_POWER_SUPPLY=y +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_RCU=y +CONFIG_PRINTK_TIME=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_PROC_EVENTS=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_PROC_PID_CPUSET=y +# CONFIG_QFMT_V1 is not set +# CONFIG_QFMT_V2 is not set +CONFIG_QUOTA=y +CONFIG_QUOTACTL=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_RCU_BOOST is not set +CONFIG_RCU_CPU_STALL_VERBOSE=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RD_BZIP2=y +CONFIG_RD_GZIP=y +CONFIG_RD_LZ4=y +CONFIG_RD_LZMA=y +CONFIG_RD_LZO=y +CONFIG_RD_XZ=y +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +CONFIG_REGULATOR_FIXED_VOLTAGE=y +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +CONFIG_RELAY=y +CONFIG_RESET_CONTROLLER=y +CONFIG_RESOURCE_COUNTERS=y +# CONFIG_RFKILL_REGULATOR is not set +CONFIG_RFS_ACCEL=y +CONFIG_RPS=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_SUNXI=y +CONFIG_SATA_AHCI_PLATFORM=y +# CONFIG_SATA_RCAR is not set +CONFIG_SCHED_HRTICK=y +CONFIG_SCSI=y +CONFIG_SECURITYFS=y +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_8250_NR_UARTS=8 +CONFIG_SERIAL_8250_RUNTIME_UARTS=8 +CONFIG_SERIAL_8250_SYSRQ=y +CONFIG_SERIO=y +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_OLPC_APSP is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +CONFIG_SLUB_CPU_PARTIAL=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_DEBUG_ON is not set +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_SPARSE_IRQ=y +# CONFIG_STAGING is not set +CONFIG_STOP_MACHINE=y +CONFIG_STRICT_DEVMEM=y +CONFIG_SUN4I_EMAC=y +CONFIG_SUN4I_TIMER=y +CONFIG_SWP_EMULATE=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASK_XACCT=y +# CONFIG_TCP_CONG_ADVANCED is not set +# CONFIG_THUMB2_KERNEL is not set +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_UID16=y +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_COMMON=y +CONFIG_USB_DEBUG=y +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +CONFIG_USB_NET_AX88179_178A=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SUNXI_EHCI=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_USBNET=y +# CONFIG_USER_NS is not set +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_USE_OF=y +CONFIG_UTS_NS=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_WATCHDOG is not set +# CONFIG_XEN is not set +CONFIG_XFRM_ALGO=y +CONFIG_XFRM_USER=y +CONFIG_XPS=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_ARMTHUMB=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_ZBOOT_ROM_TEXT=0 +# CONFIG_ZBUD is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZONE_DMA_FLAG=0 diff --git a/target/linux/sunxi/cortex-a7/profiles/100-generic.mk b/target/linux/sunxi/cortex-a7/profiles/100-generic.mk deleted file mode 100644 index ca4db9c8ae..0000000000 --- a/target/linux/sunxi/cortex-a7/profiles/100-generic.mk +++ /dev/null @@ -1,18 +0,0 @@ -# -# Copyright (C) 2013 OpenWrt.org -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -define Profile/Generic - NAME:=Generic (default) - PACKAGES:= \ - uboot-envtools -endef - -define Profile/Generic/Description - Package set compatible with most Allwinner A20, A31 and A31s SoC based boards. -endef - -$(eval $(call Profile,Generic)) diff --git a/target/linux/sunxi/cortex-a7/target.mk b/target/linux/sunxi/cortex-a7/target.mk deleted file mode 100644 index 1267eef30b..0000000000 --- a/target/linux/sunxi/cortex-a7/target.mk +++ /dev/null @@ -1,11 +0,0 @@ -# -# Copyright (C) 2013 OpenWrt.org -# - -BOARDNAME:=A20, A31 and A31s -SUBTARGET:=cortex-a7 -CPU_TYPE:=cortex-a7 - -define Target/Description - Allwinner A20, A31 and A31s SoC -endef diff --git a/target/linux/sunxi/cortex-a8/profiles/100-generic.mk b/target/linux/sunxi/cortex-a8/profiles/100-generic.mk deleted file mode 100644 index 272ec815d7..0000000000 --- a/target/linux/sunxi/cortex-a8/profiles/100-generic.mk +++ /dev/null @@ -1,18 +0,0 @@ -# -# Copyright (C) 2013 OpenWrt.org -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -define Profile/Generic - NAME:=Generic (default) - PACKAGES:= \ - uboot-envtools -endef - -define Profile/Generic/Description - Package set compatible with most Allwinner A10, A10s and A13 SoC based boards. -endef - -$(eval $(call Profile,Generic)) diff --git a/target/linux/sunxi/cortex-a8/profiles/110-cubieboard.mk b/target/linux/sunxi/cortex-a8/profiles/110-cubieboard.mk deleted file mode 100644 index a08a53f4b6..0000000000 --- a/target/linux/sunxi/cortex-a8/profiles/110-cubieboard.mk +++ /dev/null @@ -1,14 +0,0 @@ -# -# Copyright (C) 2013 OpenWrt.org -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -define Profile/CUBIEBOARD - NAME:=Cubieboard - PACKAGES:= \ - uboot-envtools -endef - -$(eval $(call Profile,CUBIEBOARD)) diff --git a/target/linux/sunxi/cortex-a8/target.mk b/target/linux/sunxi/cortex-a8/target.mk deleted file mode 100644 index 15984a6d2c..0000000000 --- a/target/linux/sunxi/cortex-a8/target.mk +++ /dev/null @@ -1,11 +0,0 @@ -# -# Copyright (C) 2013 OpenWrt.org -# - -BOARDNAME:=A10, A10s and A13 -SUBTARGET:=cortex-a8 -CPU_TYPE:=cortex-a8 - -define Target/Description - Allwinner A10, A10s and A13 SoC -endef diff --git a/target/linux/sunxi/image/Makefile b/target/linux/sunxi/image/Makefile index 3a9f64d9af..2d7a603ad1 100644 --- a/target/linux/sunxi/image/Makefile +++ b/target/linux/sunxi/image/Makefile @@ -7,21 +7,19 @@ include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/image.mk -define sanitize_profile_name -$(shell echo $(PROFILE) | tr '[:upper:]' '[:lower:]' | sed 's/_/-/g') -endef - -define Image/BuildKernel/Template +BOARDS:= \ + sun4i-a10-cubieboard \ + sun5i-a13-olinuxino \ + sun7i-a20-olinuxino-micro \ + sun7i-a20-cubieboard2 - $(CP) $(KDIR)/zImage $(BIN_DIR)/$(IMG_PREFIX)-zImage - echo -ne '\x00\x00\x00\x00' >> $(BIN_DIR)/$(IMG_PREFIX)-zImage - $(call Image/BuildKernel/MkuImage, \ - none, 0x40008000, 0x40008000, \ - $(BIN_DIR)/$(IMG_PREFIX)-zImage, \ - $(BIN_DIR)/$(IMG_PREFIX)-uImage \ - ) - - ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),) +define Image/BuildKernel + mkimage -A arm -O linux -T kernel -C none \ + -a 0x40008000 -e 0x40008000 \ + -n 'ARM OpenWrt Linux-$(LINUX_VERSION)' \ + -d $(KDIR)/zImage $(BIN_DIR)/$(IMG_PREFIX)-uImage + + ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),) $(CP) $(KDIR)/zImage-initramfs $(BIN_DIR)/$(IMG_PREFIX)-zImage-initramfs echo -ne '\x00\x00\x00\x00' >> $(BIN_DIR)/$(IMG_PREFIX)-zImage-initramfs $(call Image/BuildKernel/MkuImage, \ @@ -29,93 +27,15 @@ define Image/BuildKernel/Template $(BIN_DIR)/$(IMG_PREFIX)-zImage-initramfs, \ $(BIN_DIR)/$(IMG_PREFIX)-uImage-initramfs \ ) - endif - - ifneq ($(1),) - $(CP) $(LINUX_DIR)/arch/arm/boot/dts/$(1).dtb $(BIN_DIR)/$(IMG_PREFIX)-$(1).dtb - - $(CP) $(KDIR)/zImage $(BIN_DIR)/$(IMG_PREFIX)-$(call sanitize_profile_name)-zImage - cat $(BIN_DIR)/$(IMG_PREFIX)-$(1).dtb >> $(BIN_DIR)/$(IMG_PREFIX)-$(call sanitize_profile_name)-zImage - $(call Image/BuildKernel/MkuImage, \ - none, 0x40008000, 0x40008000, \ - $(BIN_DIR)/$(IMG_PREFIX)-$(call sanitize_profile_name)-zImage, \ - $(BIN_DIR)/$(IMG_PREFIX)-$(call sanitize_profile_name)-uImage \ - ) + endif - ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),) - $(CP) $(KDIR)/zImage-initramfs $(BIN_DIR)/$(IMG_PREFIX)-$(call sanitize_profile_name)-zImage-initramfs - cat $(BIN_DIR)/$(IMG_PREFIX)-$(1).dtb >> $(BIN_DIR)/$(IMG_PREFIX)-$(call sanitize_profile_name)-zImage-initramfs - $(call Image/BuildKernel/MkuImage, \ - none, 0x40008000, 0x40008000, \ - $(BIN_DIR)/$(IMG_PREFIX)-$(call sanitize_profile_name)-zImage-initramfs, \ - $(BIN_DIR)/$(IMG_PREFIX)-$(call sanitize_profile_name)-uImage-initramfs \ + $(foreach board,$(BOARDS), + $(CP) $(LINUX_DIR)/arch/arm/boot/dts/$(board).dtb $(BIN_DIR)/ ) - endif - endif -endef - -define Image/InstallKernel/Template - - ifneq ($(CONFIG_TARGET_ROOTFS_INCLUDE_KERNEL),) - $(INSTALL_DIR) $(TARGET_DIR)/boot - ifneq ($(CONFIG_TARGET_ROOTFS_INCLUDE_UIMAGE),) - $(CP) $(BIN_DIR)/$(IMG_PREFIX)-uImage $(TARGET_DIR)/boot/ - ln -sf $(IMG_PREFIX)-uImage $(TARGET_DIR)/boot/uImage - endif - ifneq ($(CONFIG_TARGET_ROOTFS_INCLUDE_ZIMAGE),) - $(CP) $(BIN_DIR)/$(IMG_PREFIX)-zImage $(TARGET_DIR)/boot/ - ln -sf $(IMG_PREFIX)-zImage $(TARGET_DIR)/boot/zImage - endif - endif - - ifneq ($(CONFIG_TARGET_ROOTFS_INCLUDE_DTB),) - $(INSTALL_DIR) $(TARGET_DIR)/boot - ifneq ($(1),) - $(CP) $(BIN_DIR)/$(IMG_PREFIX)-$(1).dtb $(TARGET_DIR)/boot/ - ln -sf $(IMG_PREFIX)-$(1).dtb $(TARGET_DIR)/boot/$(1).dtb - endif - endif -endef - -define Image/mkfs/targz - - $(TAR) -czpf $(BIN_DIR)/$(IMG_PREFIX)-$(call sanitize_profile_name)-rootfs.tar.gz --numeric-owner --owner=0 --group=0 -C $(TARGET_DIR)/ . -endef - -define Image/Build/ubifs - - ifneq ($($(PROFILE)_UBIFS_OPTS),) - $(CP) $(KDIR)/root.ubifs $(BIN_DIR)/$(IMG_PREFIX)-$(call sanitize_profile_name)-rootfs.ubifs - endif -endef - -define Image/Build/ubi - - ifneq ($($(PROFILE)_UBI_OPTS),) - $(CP) $(KDIR)/root.ubi $(BIN_DIR)/$(IMG_PREFIX)-$(call sanitize_profile_name)-rootfs.ubi - endif -endef - - -Image/BuildKernel/Template/generic=$(call Image/BuildKernel/Template) -Image/InstallKernel/Template/generic=$(call Image/InstallKernel/Template) - -Image/BuildKernel/Template/CUBIEBOARD=$(call Image/BuildKernel/Template,sun4i-a10-cubieboard) -Image/InstallKernel/Template/CUBIEBOARD=$(call Image/InstallKernel/Template,sun4i-a10-cubieboard) - -define Image/BuildKernel - $(call Image/BuildKernel/Template/$(PROFILE)) -endef - -define Image/InstallKernel - $(call Image/InstallKernel/Template/$(PROFILE)) endef define Image/Build - $(if $(Image/Build/$(1)), \ - $(call Image/Build/$(1),$(1)), \ - $(CP) $(KDIR)/root.$(1) $(BIN_DIR)/$(IMG_PREFIX)-$(call sanitize_profile_name)-$(1).img \ - ) + $(call Image/Build/$(1),$(1)) endef $(eval $(call BuildImage)) diff --git a/target/linux/sunxi/patches-3.12/100-clk-sunxi_register_factors.patch b/target/linux/sunxi/patches-3.12/100-clk-sunxi_register_factors.patch new file mode 100644 index 0000000000..c949eeb69f --- /dev/null +++ b/target/linux/sunxi/patches-3.12/100-clk-sunxi_register_factors.patch @@ -0,0 +1,220 @@ +From 337d479970b0c8493ee3e8b8d89fb80ee39333a6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar> +Date: Sun, 5 May 2013 21:26:23 -0300 +Subject: [PATCH] clk: sunxi: register factors clocks behind composite +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit reworks factors clock registration to be done behind a +composite clock. This allows us to additionally add a gate, mux or +divisors, as it will be needed by some future PLLs. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +--- + drivers/clk/sunxi/clk-factors.c | 63 +-------------------------------------- + drivers/clk/sunxi/clk-factors.h | 16 +++++----- + drivers/clk/sunxi/clk-sunxi.c | 66 ++++++++++++++++++++++++++++++++++++++--- + 3 files changed, 72 insertions(+), 73 deletions(-) + +diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c +index 88523f9..6e3926c 100644 +--- a/drivers/clk/sunxi/clk-factors.c ++++ b/drivers/clk/sunxi/clk-factors.c +@@ -30,14 +30,6 @@ + * parent - fixed parent. No clk_set_parent support + */ + +-struct clk_factors { +- struct clk_hw hw; +- void __iomem *reg; +- struct clk_factors_config *config; +- void (*get_factors) (u32 *rate, u32 parent, u8 *n, u8 *k, u8 *m, u8 *p); +- spinlock_t *lock; +-}; +- + #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw) + + #define SETMASK(len, pos) (((-1U) >> (31-len)) << (pos)) +@@ -120,61 +112,8 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, + return 0; + } + +-static const struct clk_ops clk_factors_ops = { ++const struct clk_ops clk_factors_ops = { + .recalc_rate = clk_factors_recalc_rate, + .round_rate = clk_factors_round_rate, + .set_rate = clk_factors_set_rate, + }; +- +-/** +- * clk_register_factors - register a factors clock with +- * the clock framework +- * @dev: device registering this clock +- * @name: name of this clock +- * @parent_name: name of clock's parent +- * @flags: framework-specific flags +- * @reg: register address to adjust factors +- * @config: shift and width of factors n, k, m and p +- * @get_factors: function to calculate the factors for a given frequency +- * @lock: shared register lock for this clock +- */ +-struct clk *clk_register_factors(struct device *dev, const char *name, +- const char *parent_name, +- unsigned long flags, void __iomem *reg, +- struct clk_factors_config *config, +- void (*get_factors)(u32 *rate, u32 parent, +- u8 *n, u8 *k, u8 *m, u8 *p), +- spinlock_t *lock) +-{ +- struct clk_factors *factors; +- struct clk *clk; +- struct clk_init_data init; +- +- /* allocate the factors */ +- factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL); +- if (!factors) { +- pr_err("%s: could not allocate factors clk\n", __func__); +- return ERR_PTR(-ENOMEM); +- } +- +- init.name = name; +- init.ops = &clk_factors_ops; +- init.flags = flags; +- init.parent_names = (parent_name ? &parent_name : NULL); +- init.num_parents = (parent_name ? 1 : 0); +- +- /* struct clk_factors assignments */ +- factors->reg = reg; +- factors->config = config; +- factors->lock = lock; +- factors->hw.init = &init; +- factors->get_factors = get_factors; +- +- /* register the clock */ +- clk = clk_register(dev, &factors->hw); +- +- if (IS_ERR(clk)) +- kfree(factors); +- +- return clk; +-} +diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h +index f49851c..02e1a43 100644 +--- a/drivers/clk/sunxi/clk-factors.h ++++ b/drivers/clk/sunxi/clk-factors.h +@@ -17,11 +17,13 @@ struct clk_factors_config { + u8 pwidth; + }; + +-struct clk *clk_register_factors(struct device *dev, const char *name, +- const char *parent_name, +- unsigned long flags, void __iomem *reg, +- struct clk_factors_config *config, +- void (*get_factors) (u32 *rate, u32 parent_rate, +- u8 *n, u8 *k, u8 *m, u8 *p), +- spinlock_t *lock); ++struct clk_factors { ++ struct clk_hw hw; ++ void __iomem *reg; ++ struct clk_factors_config *config; ++ void (*get_factors) (u32 *rate, u32 parent, u8 *n, u8 *k, u8 *m, u8 *p); ++ spinlock_t *lock; ++}; ++ ++extern const struct clk_ops clk_factors_ops; + #endif +diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c +index 34ee69f..6aed57f 100644 +--- a/drivers/clk/sunxi/clk-sunxi.c ++++ b/drivers/clk/sunxi/clk-sunxi.c +@@ -256,7 +256,11 @@ static void sun4i_get_apb1_factors(u32 *freq, u32 parent_rate, + * sunxi_factors_clk_setup() - Setup function for factor clocks + */ + ++#define SUNXI_FACTORS_MUX_MASK 0x3 ++ + struct factors_data { ++ int enable; ++ int mux; + struct clk_factors_config *table; + void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p); + }; +@@ -307,16 +311,70 @@ static void __init sunxi_factors_clk_setup(struct device_node *node, + struct factors_data *data) + { + struct clk *clk; ++ struct clk_factors *factors; ++ struct clk_gate *gate; ++ struct clk_mux *mux; ++ struct clk_hw *gate_hw = NULL; ++ struct clk_hw *mux_hw = NULL; + const char *clk_name = node->name; +- const char *parent; ++ const char *parents[5]; + void *reg; ++ int i = 0; + + reg = of_iomap(node, 0); + +- parent = of_clk_get_parent_name(node, 0); ++ /* if we have a mux, we will have >1 parents */ ++ while (i < 5 && (parents[i] = of_clk_get_parent_name(node, i)) != NULL) ++ i++; ++ ++ factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL); ++ if (!factors) ++ return; ++ ++ /* Add a gate if this factor clock can be gated */ ++ if (data->enable) { ++ gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); ++ if (!gate) { ++ kfree(factors); ++ return; ++ } ++ ++ /* set up gate properties */ ++ gate->reg = reg; ++ gate->bit_idx = data->enable; ++ gate->lock = &clk_lock; ++ gate_hw = &gate->hw; ++ } + +- clk = clk_register_factors(NULL, clk_name, parent, 0, reg, +- data->table, data->getter, &clk_lock); ++ /* Add a mux if this factor clock can be muxed */ ++ if (data->mux) { ++ mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); ++ if (!mux) { ++ kfree(factors); ++ kfree(gate); ++ return; ++ } ++ ++ /* set up gate properties */ ++ mux->reg = reg; ++ mux->shift = data->mux; ++ mux->mask = SUNXI_FACTORS_MUX_MASK; ++ mux->lock = &clk_lock; ++ mux_hw = &mux->hw; ++ } ++ ++ /* set up factors properties */ ++ factors->reg = reg; ++ factors->config = data->table; ++ factors->get_factors = data->getter; ++ factors->lock = &clk_lock; ++ ++ clk = clk_register_composite(NULL, clk_name, ++ parents, i, ++ mux_hw, &clk_mux_ops, ++ &factors->hw, &clk_factors_ops, ++ gate_hw, &clk_gate_ops, ++ i ? 0 : CLK_IS_ROOT); + + if (!IS_ERR(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/101-clk-sunxi_add-gating-pll1.patch b/target/linux/sunxi/patches-3.12/101-clk-sunxi_add-gating-pll1.patch new file mode 100644 index 0000000000..00519b815a --- /dev/null +++ b/target/linux/sunxi/patches-3.12/101-clk-sunxi_add-gating-pll1.patch @@ -0,0 +1,51 @@ +From 68557a66b206de79a4556d393d51865407525d52 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar> +Date: Mon, 6 May 2013 09:59:00 -0300 +Subject: [PATCH] clk: sunxi: add gating support to PLL1 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit adds gating support to PLL1 on the clock driver. This makes +the PLL1 implementation fully compatible with PLL4 as well. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +--- + Documentation/devicetree/bindings/clock/sunxi.txt | 2 +- + drivers/clk/sunxi/clk-sunxi.c | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt +index 00a5c264..7d9245f 100644 +--- a/Documentation/devicetree/bindings/clock/sunxi.txt ++++ b/Documentation/devicetree/bindings/clock/sunxi.txt +@@ -7,7 +7,7 @@ This binding uses the common clock binding[1]. + Required properties: + - compatible : shall be one of the following: + "allwinner,sun4i-osc-clk" - for a gatable oscillator +- "allwinner,sun4i-pll1-clk" - for the main PLL clock ++ "allwinner,sun4i-pll1-clk" - for the main PLL clock and PLL4 + "allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31 + "allwinner,sun4i-cpu-clk" - for the CPU multiplexer clock + "allwinner,sun4i-axi-clk" - for the AXI clock +diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c +index 6aed57f..c0b0675 100644 +--- a/drivers/clk/sunxi/clk-sunxi.c ++++ b/drivers/clk/sunxi/clk-sunxi.c +@@ -293,11 +293,13 @@ struct factors_data { + }; + + static const struct factors_data sun4i_pll1_data __initconst = { ++ .enable = 31, + .table = &sun4i_pll1_config, + .getter = sun4i_get_pll1_factors, + }; + + static const struct factors_data sun6i_a31_pll1_data __initconst = { ++ .enable = 31, + .table = &sun6i_a31_pll1_config, + .getter = sun6i_a31_get_pll1_factors, + }; +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/102-clk-sunxi_add_pll4.patch b/target/linux/sunxi/patches-3.12/102-clk-sunxi_add_pll4.patch new file mode 100644 index 0000000000..65fb3e66df --- /dev/null +++ b/target/linux/sunxi/patches-3.12/102-clk-sunxi_add_pll4.patch @@ -0,0 +1,94 @@ +From 73bff3c4c33a2bfbddc593fad53c6c58af93bfab Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar> +Date: Mon, 6 May 2013 11:03:41 -0300 +Subject: [PATCH] ARM: sunxi: add PLL4 support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit adds the PLL4 definition to the sun4i, sun5i and sun7i +device trees. PLL4 is compatible with PLL1. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +--- + arch/arm/boot/dts/sun4i-a10.dtsi | 7 +++++++ + arch/arm/boot/dts/sun5i-a10s.dtsi | 7 +++++++ + arch/arm/boot/dts/sun5i-a13.dtsi | 7 +++++++ + arch/arm/boot/dts/sun7i-a20.dtsi | 7 +++++++ + 4 files changed, 28 insertions(+) + +diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi +index 319cc6b..a6c1cae 100644 +--- a/arch/arm/boot/dts/sun4i-a10.dtsi ++++ b/arch/arm/boot/dts/sun4i-a10.dtsi +@@ -66,6 +66,13 @@ + clocks = <&osc24M>; + }; + ++ pll4: pll4@01c20018 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-pll1-clk"; ++ reg = <0x01c20018 0x4>; ++ clocks = <&osc24M>; ++ }; ++ + /* dummy is 200M */ + cpu: cpu@01c20054 { + #clock-cells = <0>; +diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi +index 5247674..c3f4eed 100644 +--- a/arch/arm/boot/dts/sun5i-a10s.dtsi ++++ b/arch/arm/boot/dts/sun5i-a10s.dtsi +@@ -63,6 +63,13 @@ + clocks = <&osc24M>; + }; + ++ pll4: pll4@01c20018 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-pll1-clk"; ++ reg = <0x01c20018 0x4>; ++ clocks = <&osc24M>; ++ }; ++ + /* dummy is 200M */ + cpu: cpu@01c20054 { + #clock-cells = <0>; +diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi +index ce8ef2a..8c4a9c3 100644 +--- a/arch/arm/boot/dts/sun5i-a13.dtsi ++++ b/arch/arm/boot/dts/sun5i-a13.dtsi +@@ -67,6 +67,13 @@ + clocks = <&osc24M>; + }; + ++ pll4: pll4@01c20018 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-pll1-clk"; ++ reg = <0x01c20018 0x4>; ++ clocks = <&osc24M>; ++ }; ++ + /* dummy is 200M */ + cpu: cpu@01c20054 { + #clock-cells = <0>; +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index 282c775..21bf143 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -62,6 +62,13 @@ + clocks = <&osc24M>; + }; + ++ pll4: pll4@01c20018 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-pll1-clk"; ++ reg = <0x01c20018 0x4>; ++ clocks = <&osc24M>; ++ }; ++ + /* + * This is a dummy clock, to be used as placeholder on + * other mux clocks when a specific parent clock is not +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/103-clk-sunxi_add_pll5-6.patch b/target/linux/sunxi/patches-3.12/103-clk-sunxi_add_pll5-6.patch new file mode 100644 index 0000000000..f680a42e1f --- /dev/null +++ b/target/linux/sunxi/patches-3.12/103-clk-sunxi_add_pll5-6.patch @@ -0,0 +1,309 @@ +From cad227619badf2a0ff2593d9935fedc84d5ef1ef Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar> +Date: Sun, 26 May 2013 14:23:50 -0300 +Subject: [PATCH] clk: sunxi: add PLL5 and PLL6 support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit implements PLL5 and PLL6 support on the sunxi clock driver. +These PLLs use a similar factor clock, but differ on their outputs. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +--- + Documentation/devicetree/bindings/clock/sunxi.txt | 2 + + drivers/clk/sunxi/clk-sunxi.c | 182 +++++++++++++++++++++- + 2 files changed, 177 insertions(+), 7 deletions(-) + +diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt +index 7d9245f..773f3ae 100644 +--- a/Documentation/devicetree/bindings/clock/sunxi.txt ++++ b/Documentation/devicetree/bindings/clock/sunxi.txt +@@ -9,6 +9,8 @@ Required properties: + "allwinner,sun4i-osc-clk" - for a gatable oscillator + "allwinner,sun4i-pll1-clk" - for the main PLL clock and PLL4 + "allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31 ++ "allwinner,sun4i-pll5-clk" - for the PLL5 clock ++ "allwinner,sun4i-pll6-clk" - for the PLL6 clock + "allwinner,sun4i-cpu-clk" - for the CPU multiplexer clock + "allwinner,sun4i-axi-clk" - for the AXI clock + "allwinner,sun4i-axi-gates-clk" - for the AXI gates +diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c +index c0b0675..6947ba9 100644 +--- a/drivers/clk/sunxi/clk-sunxi.c ++++ b/drivers/clk/sunxi/clk-sunxi.c +@@ -210,6 +210,40 @@ static void sun6i_a31_get_pll1_factors(u32 *freq, u32 parent_rate, + } + + /** ++ * sun4i_get_pll5_factors() - calculates n, k factors for PLL5 ++ * PLL5 rate is calculated as follows ++ * rate = parent_rate * n * (k + 1) ++ * parent_rate is always 24Mhz ++ */ ++ ++static void sun4i_get_pll5_factors(u32 *freq, u32 parent_rate, ++ u8 *n, u8 *k, u8 *m, u8 *p) ++{ ++ u8 div; ++ ++ /* Normalize value to a 24M multiple */ ++ div = *freq / 24000000; ++ *freq = 24000000 * div; ++ ++ /* we were called to round the frequency, we can now return */ ++ if (n == NULL) ++ return; ++ ++ if (div < 31) ++ *k = 0; ++ else if (div / 2 < 31) ++ *k = 1; ++ else if (div / 3 < 31) ++ *k = 2; ++ else ++ *k = 3; ++ ++ *n = DIV_ROUND_UP(div, (*k+1)); ++} ++ ++ ++ ++/** + * sun4i_get_apb1_factors() - calculates m, p factors for APB1 + * APB1 rate is calculated as follows + * rate = (parent_rate >> p) / (m + 1); +@@ -285,6 +319,13 @@ struct factors_data { + .mwidth = 2, + }; + ++static struct clk_factors_config sun4i_pll5_config = { ++ .nshift = 8, ++ .nwidth = 5, ++ .kshift = 4, ++ .kwidth = 2, ++}; ++ + static struct clk_factors_config sun4i_apb1_config = { + .mshift = 0, + .mwidth = 5, +@@ -304,13 +345,19 @@ struct factors_data { + .getter = sun6i_a31_get_pll1_factors, + }; + ++static const struct factors_data sun4i_pll5_data __initconst = { ++ .enable = 31, ++ .table = &sun4i_pll5_config, ++ .getter = sun4i_get_pll5_factors, ++}; ++ + static const struct factors_data sun4i_apb1_data __initconst = { + .table = &sun4i_apb1_config, + .getter = sun4i_get_apb1_factors, + }; + +-static void __init sunxi_factors_clk_setup(struct device_node *node, +- struct factors_data *data) ++static struct clk * __init sunxi_factors_clk_setup(struct device_node *node, ++ const struct factors_data *data) + { + struct clk *clk; + struct clk_factors *factors; +@@ -321,6 +368,7 @@ static void __init sunxi_factors_clk_setup(struct device_node *node, + const char *clk_name = node->name; + const char *parents[5]; + void *reg; ++ unsigned long flags; + int i = 0; + + reg = of_iomap(node, 0); +@@ -331,14 +379,14 @@ static void __init sunxi_factors_clk_setup(struct device_node *node, + + factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL); + if (!factors) +- return; ++ return NULL; + + /* Add a gate if this factor clock can be gated */ + if (data->enable) { + gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); + if (!gate) { + kfree(factors); +- return; ++ return NULL; + } + + /* set up gate properties */ +@@ -354,7 +402,7 @@ static void __init sunxi_factors_clk_setup(struct device_node *node, + if (!mux) { + kfree(factors); + kfree(gate); +- return; ++ return NULL; + } + + /* set up gate properties */ +@@ -371,17 +419,21 @@ static void __init sunxi_factors_clk_setup(struct device_node *node, + factors->get_factors = data->getter; + factors->lock = &clk_lock; + ++ /* We should not disable pll5, it powers the RAM */ ++ flags = !strcmp("pll5", clk_name) ? CLK_IGNORE_UNUSED : 0; ++ + clk = clk_register_composite(NULL, clk_name, + parents, i, + mux_hw, &clk_mux_ops, + &factors->hw, &clk_factors_ops, +- gate_hw, &clk_gate_ops, +- i ? 0 : CLK_IS_ROOT); ++ gate_hw, &clk_gate_ops, flags); + + if (!IS_ERR(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); + } ++ ++ return clk; + } + + +@@ -616,6 +668,112 @@ static void __init sunxi_gates_clk_setup(struct device_node *node, + of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + } + ++ ++ ++/** ++ * sunxi_divs_clk_setup() - Setup function for leaf divisors on clocks ++ */ ++ ++#define SUNXI_DIVS_MAX_QTY 2 ++#define SUNXI_DIVISOR_WIDTH 2 ++ ++struct divs_data { ++ const struct factors_data *factors; /* data for the factor clock */ ++ struct { ++ u8 fixed; /* is it a fixed divisor? if not... */ ++ struct clk_div_table *table; /* is it a table based divisor? */ ++ u8 shift; /* otherwise it's a normal divisor with this shift */ ++ u8 pow; /* is it power-of-two based? */ ++ } div[SUNXI_DIVS_MAX_QTY]; ++}; ++ ++static struct clk_div_table pll6_sata_table[] = { ++ { .val = 0, .div = 6, }, ++ { .val = 1, .div = 12, }, ++ { .val = 2, .div = 18, }, ++ { .val = 3, .div = 24, }, ++ { } /* sentinel */ ++}; ++ ++static const struct divs_data pll5_divs_data __initconst = { ++ .factors = &sun4i_pll5_data, ++ .div = { ++ { .shift = 0, .pow = 0, }, /* M, DDR */ ++ { .shift = 16, .pow = 1, }, /* P, other */ ++ } ++}; ++ ++static const struct divs_data pll6_divs_data __initconst = { ++ .factors = &sun4i_pll5_data, ++ .div = { ++ { .shift = 0, .table = pll6_sata_table }, /* M, SATA */ ++ { .fixed = 2 }, /* P, other */ ++ } ++}; ++ ++static void __init sunxi_divs_clk_setup(struct device_node *node, ++ struct divs_data *data) ++{ ++ struct clk_onecell_data *clk_data; ++ const char *parent = node->name; ++ const char *clk_name; ++ struct clk **clks, *pclk; ++ void *reg; ++ int i = 0; ++ int flags, clkflags; ++ ++ /* Set up factor clock that we will be dividing */ ++ pclk = sunxi_factors_clk_setup(node, data->factors); ++ ++ reg = of_iomap(node, 0); ++ ++ clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL); ++ if (!clk_data) ++ return; ++ clks = kzalloc(SUNXI_DIVS_MAX_QTY * sizeof(struct clk *), GFP_KERNEL); ++ if (!clks) { ++ kfree(clk_data); ++ return; ++ } ++ clk_data->clks = clks; ++ ++ /* It's not a good idea to have automatic reparenting changing ++ * our RAM clock! */ ++ clkflags = !strcmp("pll5", parent) ? 0 : CLK_SET_RATE_PARENT; ++ ++ for (i = 0; i < SUNXI_DIVS_MAX_QTY; i++) { ++ if (of_property_read_string_index(node, "clock-output-names", ++ i, &clk_name) != 0) ++ break; ++ ++ if (data->div[i].fixed) { ++ clks[i] = clk_register_fixed_factor(NULL, clk_name, ++ parent, clkflags, ++ 1, data->div[i].fixed); ++ } else { ++ flags = data->div[i].pow ? CLK_DIVIDER_POWER_OF_TWO : 0; ++ clks[i] = clk_register_divider_table(NULL, clk_name, ++ parent, clkflags, reg, ++ data->div[i].shift, ++ SUNXI_DIVISOR_WIDTH, flags, ++ data->div[i].table, &clk_lock); ++ } ++ ++ WARN_ON(IS_ERR(clk_data->clks[i])); ++ clk_register_clkdev(clks[i], clk_name, NULL); ++ } ++ ++ /* The last clock available on the getter is the parent */ ++ clks[i++] = pclk; ++ ++ /* Adjust to the real max */ ++ clk_data->clk_num = i; ++ ++ of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); ++} ++ ++ ++ + /* Matches for factors clocks */ + static const struct of_device_id clk_factors_match[] __initconst = { + {.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,}, +@@ -633,6 +791,13 @@ static void __init sunxi_gates_clk_setup(struct device_node *node, + {} + }; + ++/* Matches for divided outputs */ ++static const struct of_device_id clk_divs_match[] __initconst = { ++ {.compatible = "allwinner,sun4i-pll5-clk", .data = &pll5_divs_data,}, ++ {.compatible = "allwinner,sun4i-pll6-clk", .data = &pll6_divs_data,}, ++ {} ++}; ++ + /* Matches for mux clocks */ + static const struct of_device_id clk_mux_match[] __initconst = { + {.compatible = "allwinner,sun4i-cpu-clk", .data = &sun4i_cpu_mux_data,}, +@@ -688,6 +853,9 @@ void __init sunxi_init_clocks(void) + /* Register divider clocks */ + of_sunxi_table_clock_setup(clk_div_match, sunxi_divider_clk_setup); + ++ /* Register divided output clocks */ ++ of_sunxi_table_clock_setup(clk_divs_match, sunxi_divs_clk_setup); ++ + /* Register mux clocks */ + of_sunxi_table_clock_setup(clk_mux_match, sunxi_mux_clk_setup); + +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/104-arm-sunxi_add_pll5-6_dts.patch b/target/linux/sunxi/patches-3.12/104-arm-sunxi_add_pll5-6_dts.patch new file mode 100644 index 0000000000..bd9221207a --- /dev/null +++ b/target/linux/sunxi/patches-3.12/104-arm-sunxi_add_pll5-6_dts.patch @@ -0,0 +1,197 @@ +From 4f40ad1587e9435a2085703fa2a7d7c9245306b2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar> +Date: Sun, 26 May 2013 14:08:59 -0300 +Subject: [PATCH] ARM: sunxi: add PLL5 and PLL6 support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit adds PLL5 and PLL6 nodes to the sun4i, sun5i and sun7i +device trees. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +--- + arch/arm/boot/dts/sun4i-a10.dtsi | 19 +++++++++++++++++-- + arch/arm/boot/dts/sun5i-a10s.dtsi | 19 +++++++++++++++++-- + arch/arm/boot/dts/sun5i-a13.dtsi | 19 +++++++++++++++++-- + arch/arm/boot/dts/sun7i-a20.dtsi | 28 ++++++++++++++++------------ + 4 files changed, 67 insertions(+), 18 deletions(-) + +diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi +index a6c1cae..5e2fc45 100644 +--- a/arch/arm/boot/dts/sun4i-a10.dtsi ++++ b/arch/arm/boot/dts/sun4i-a10.dtsi +@@ -73,6 +73,22 @@ + clocks = <&osc24M>; + }; + ++ pll5: pll5@01c20020 { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun4i-pll5-clk"; ++ reg = <0x01c20020 0x4>; ++ clocks = <&osc24M>; ++ clock-output-names = "pll5_ddr", "pll5_other"; ++ }; ++ ++ pll6: pll6@01c20028 { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun4i-pll6-clk"; ++ reg = <0x01c20028 0x4>; ++ clocks = <&osc24M>; ++ clock-output-names = "pll6_sata", "pll6_other", "pll6"; ++ }; ++ + /* dummy is 200M */ + cpu: cpu@01c20054 { + #clock-cells = <0>; +@@ -138,12 +154,11 @@ + "apb0_ir1", "apb0_keypad"; + }; + +- /* dummy is pll62 */ + apb1_mux: apb1_mux@01c20058 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-apb1-mux-clk"; + reg = <0x01c20058 0x4>; +- clocks = <&osc24M>, <&dummy>, <&osc32k>; ++ clocks = <&osc24M>, <&pll6 1>, <&osc32k>; + }; + + apb1: apb1@01c20058 { +diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi +index c3f4eed..b29412a 100644 +--- a/arch/arm/boot/dts/sun5i-a10s.dtsi ++++ b/arch/arm/boot/dts/sun5i-a10s.dtsi +@@ -70,6 +70,22 @@ + clocks = <&osc24M>; + }; + ++ pll5: pll5@01c20020 { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun4i-pll5-clk"; ++ reg = <0x01c20020 0x4>; ++ clocks = <&osc24M>; ++ clock-output-names = "pll5_ddr", "pll5_other"; ++ }; ++ ++ pll6: pll6@01c20028 { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun4i-pll6-clk"; ++ reg = <0x01c20028 0x4>; ++ clocks = <&osc24M>; ++ clock-output-names = "pll6_sata", "pll6_other", "pll6"; ++ }; ++ + /* dummy is 200M */ + cpu: cpu@01c20054 { + #clock-cells = <0>; +@@ -130,12 +146,11 @@ + "apb0_ir", "apb0_keypad"; + }; + +- /* dummy is pll62 */ + apb1_mux: apb1_mux@01c20058 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-apb1-mux-clk"; + reg = <0x01c20058 0x4>; +- clocks = <&osc24M>, <&dummy>, <&osc32k>; ++ clocks = <&osc24M>, <&pll6 1>, <&osc32k>; + }; + + apb1: apb1@01c20058 { +diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi +index 8c4a9c3..cded3c7 100644 +--- a/arch/arm/boot/dts/sun5i-a13.dtsi ++++ b/arch/arm/boot/dts/sun5i-a13.dtsi +@@ -74,6 +74,22 @@ + clocks = <&osc24M>; + }; + ++ pll5: pll5@01c20020 { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun4i-pll5-clk"; ++ reg = <0x01c20020 0x4>; ++ clocks = <&osc24M>; ++ clock-output-names = "pll5_ddr", "pll5_other"; ++ }; ++ ++ pll6: pll6@01c20028 { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun4i-pll6-clk"; ++ reg = <0x01c20028 0x4>; ++ clocks = <&osc24M>; ++ clock-output-names = "pll6_sata", "pll6_other", "pll6"; ++ }; ++ + /* dummy is 200M */ + cpu: cpu@01c20054 { + #clock-cells = <0>; +@@ -132,12 +148,11 @@ + clock-output-names = "apb0_codec", "apb0_pio", "apb0_ir"; + }; + +- /* dummy is pll6 */ + apb1_mux: apb1_mux@01c20058 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-apb1-mux-clk"; + reg = <0x01c20058 0x4>; +- clocks = <&osc24M>, <&dummy>, <&osc32k>; ++ clocks = <&osc24M>, <&pll6 1>, <&osc32k>; + }; + + apb1: apb1@01c20058 { +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index 21bf143..2e39ed9 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -69,23 +69,27 @@ + clocks = <&osc24M>; + }; + +- /* +- * This is a dummy clock, to be used as placeholder on +- * other mux clocks when a specific parent clock is not +- * yet implemented. It should be dropped when the driver +- * is complete. +- */ +- pll6: pll6 { +- #clock-cells = <0>; +- compatible = "fixed-clock"; +- clock-frequency = <0>; ++ pll5: pll5@01c20020 { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun4i-pll5-clk"; ++ reg = <0x01c20020 0x4>; ++ clocks = <&osc24M>; ++ clock-output-names = "pll5_ddr", "pll5_other"; ++ }; ++ ++ pll6: pll6@01c20028 { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun4i-pll6-clk"; ++ reg = <0x01c20028 0x4>; ++ clocks = <&osc24M>; ++ clock-output-names = "pll6_sata", "pll6_other", "pll6"; + }; + + cpu: cpu@01c20054 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-cpu-clk"; + reg = <0x01c20054 0x4>; +- clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll6>; ++ clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll6 1>; + }; + + axi: axi@01c20054 { +@@ -144,7 +148,7 @@ + #clock-cells = <0>; + compatible = "allwinner,sun4i-apb1-mux-clk"; + reg = <0x01c20058 0x4>; +- clocks = <&osc24M>, <&pll6>, <&osc32k>; ++ clocks = <&osc24M>, <&pll6 1>, <&osc32k>; + }; + + apb1: apb1@01c20058 { +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/105-clk-sunxi_mod0.patch b/target/linux/sunxi/patches-3.12/105-clk-sunxi_mod0.patch new file mode 100644 index 0000000000..bbb8057f7c --- /dev/null +++ b/target/linux/sunxi/patches-3.12/105-clk-sunxi_mod0.patch @@ -0,0 +1,121 @@ +From 3473e6acea4bd01ba2b334628970390207f9f4fd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar> +Date: Tue, 21 May 2013 21:25:05 -0300 +Subject: [PATCH] clk: sunxi: mod0 support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit implements support for the "module 0" type of clocks, as +used by MMC, IR, NAND, SATA and other components. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +--- + Documentation/devicetree/bindings/clock/sunxi.txt | 1 + + drivers/clk/sunxi/clk-sunxi.c | 57 +++++++++++++++++++++++ + 2 files changed, 58 insertions(+) + +diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt +index 773f3ae..ff3f61c 100644 +--- a/Documentation/devicetree/bindings/clock/sunxi.txt ++++ b/Documentation/devicetree/bindings/clock/sunxi.txt +@@ -35,6 +35,7 @@ Required properties: + "allwinner,sun7i-a20-apb1-gates-clk" - for the APB1 gates on A20 + "allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31 + "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 ++ "allwinner,sun4i-mod0-clk" - for the module 0 family of clocks + + Required properties for all clocks: + - reg : shall be the control register address for the clock. +diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c +index 6947ba9..96c01b2 100644 +--- a/drivers/clk/sunxi/clk-sunxi.c ++++ b/drivers/clk/sunxi/clk-sunxi.c +@@ -287,6 +287,47 @@ static void sun4i_get_apb1_factors(u32 *freq, u32 parent_rate, + + + /** ++ * sun4i_get_mod0_factors() - calculates m, n factors for MOD0-style clocks ++ * MMC rate is calculated as follows ++ * rate = (parent_rate >> p) / (m + 1); ++ */ ++ ++static void sun4i_get_mod0_factors(u32 *freq, u32 parent_rate, ++ u8 *n, u8 *k, u8 *m, u8 *p) ++{ ++ u8 div, calcm, calcp; ++ ++ /* These clocks can only divide, so we will never be able to achieve ++ * frequencies higher than the parent frequency */ ++ if (*freq > parent_rate) ++ *freq = parent_rate; ++ ++ div = parent_rate / *freq; ++ ++ if (div < 16) ++ calcp = 0; ++ else if (div / 2 < 16) ++ calcp = 1; ++ else if (div / 4 < 16) ++ calcp = 2; ++ else ++ calcp = 3; ++ ++ calcm = DIV_ROUND_UP(div, 1 << calcp); ++ ++ *freq = (parent_rate >> calcp) / calcm; ++ ++ /* we were called to round the frequency, we can now return */ ++ if (n == NULL) ++ return; ++ ++ *m = calcm - 1; ++ *p = calcp; ++} ++ ++ ++ ++/** + * sunxi_factors_clk_setup() - Setup function for factor clocks + */ + +@@ -333,6 +374,14 @@ struct factors_data { + .pwidth = 2, + }; + ++/* user manual says "n" but it's really "p" */ ++static struct clk_factors_config sun4i_mod0_config = { ++ .mshift = 0, ++ .mwidth = 4, ++ .pshift = 16, ++ .pwidth = 2, ++}; ++ + static const struct factors_data sun4i_pll1_data __initconst = { + .enable = 31, + .table = &sun4i_pll1_config, +@@ -356,6 +405,13 @@ struct factors_data { + .getter = sun4i_get_apb1_factors, + }; + ++static const struct factors_data sun4i_mod0_data __initconst = { ++ .enable = 31, ++ .mux = 24, ++ .table = &sun4i_mod0_config, ++ .getter = sun4i_get_mod0_factors, ++}; ++ + static struct clk * __init sunxi_factors_clk_setup(struct device_node *node, + const struct factors_data *data) + { +@@ -779,6 +835,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node, + {.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,}, + {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,}, + {.compatible = "allwinner,sun4i-apb1-clk", .data = &sun4i_apb1_data,}, ++ {.compatible = "allwinner,sun4i-mod0-clk", .data = &sun4i_mod0_data,}, + {} + }; + +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/120-split-dt-for-sun6i-sun7i.patch b/target/linux/sunxi/patches-3.12/120-split-dt-for-sun6i-sun7i.patch new file mode 100644 index 0000000000..439f7d99a1 --- /dev/null +++ b/target/linux/sunxi/patches-3.12/120-split-dt-for-sun6i-sun7i.patch @@ -0,0 +1,56 @@ +From eac8f640c624e83ef2ae267efc0769e086a64059 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Sun, 11 Aug 2013 14:35:08 +0200 +Subject: [PATCH] ARM: sunxi: Split out the DT machines for sun6i and sun7i + +The A20 and A31 SMP code have a different way of bringing up a new core. +This will prevent us from using the same set of smp_operations for the +two SoCs family. + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + arch/arm/mach-sunxi/sunxi.c | 24 ++++++++++++++++++++++-- + 1 file changed, 22 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c +index e79fb34..e0641dd 100644 +--- a/arch/arm/mach-sunxi/sunxi.c ++++ b/arch/arm/mach-sunxi/sunxi.c +@@ -133,8 +133,6 @@ static void __init sunxi_dt_init(void) + "allwinner,sun4i-a10", + "allwinner,sun5i-a10s", + "allwinner,sun5i-a13", +- "allwinner,sun6i-a31", +- "allwinner,sun7i-a20", + NULL, + }; + +@@ -143,3 +141,25 @@ static void __init sunxi_dt_init(void) + .init_time = sunxi_timer_init, + .dt_compat = sunxi_board_dt_compat, + MACHINE_END ++ ++static const char * const sun6i_board_dt_compat[] = { ++ "allwinner,sun6i-a31", ++ NULL, ++}; ++ ++DT_MACHINE_START(SUN6I_DT, "Allwinner sun6i (A31) Family") ++ .init_machine = sunxi_dt_init, ++ .init_time = sunxi_timer_init, ++ .dt_compat = sun6i_board_dt_compat, ++MACHINE_END ++ ++static const char * const sun7i_board_dt_compat[] = { ++ "allwinner,sun7i-a20", ++ NULL, ++}; ++ ++DT_MACHINE_START(SUN7I_DT, "Allwinner sun7i (A20) Family") ++ .init_machine = sunxi_dt_init, ++ .init_time = sunxi_timer_init, ++ .dt_compat = sun7i_board_dt_compat, ++MACHINE_END +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/130-sun7i-enable-i2c-ctrlers.patch b/target/linux/sunxi/patches-3.12/130-sun7i-enable-i2c-ctrlers.patch new file mode 100644 index 0000000000..ef761a66f8 --- /dev/null +++ b/target/linux/sunxi/patches-3.12/130-sun7i-enable-i2c-ctrlers.patch @@ -0,0 +1,73 @@ +From 220d6c860e0c7853aea6509ea2b5a44463c9af8b Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Sat, 31 Aug 2013 23:07:24 +0200 +Subject: [PATCH] ARM: sun7i: Enable the I2C controllers + +The Allwinner A20 shares the same I2C controller than the one that could +be found on earlier SoCs from Allwinner. There is only a few more of +these controllers. Add all of them in the DTSI. + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + arch/arm/boot/dts/sun7i-a20.dtsi | 45 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 45 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index 2e39ed9..0d0ee15 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -340,6 +340,51 @@ + status = "disabled"; + }; + ++ i2c0: i2c@01c2ac00 { ++ compatible = "allwinner,sun4i-i2c"; ++ reg = <0x01c2ac00 0x400>; ++ interrupts = <0 7 1>; ++ clocks = <&apb1_gates 0>; ++ clock-frequency = <100000>; ++ status = "disabled"; ++ }; ++ ++ i2c1: i2c@01c2b000 { ++ compatible = "allwinner,sun4i-i2c"; ++ reg = <0x01c2b000 0x400>; ++ interrupts = <0 8 1>; ++ clocks = <&apb1_gates 1>; ++ clock-frequency = <100000>; ++ status = "disabled"; ++ }; ++ ++ i2c2: i2c@01c2b400 { ++ compatible = "allwinner,sun4i-i2c"; ++ reg = <0x01c2b400 0x400>; ++ interrupts = <0 9 1>; ++ clocks = <&apb1_gates 2>; ++ clock-frequency = <100000>; ++ status = "disabled"; ++ }; ++ ++ i2c3: i2c@01c2b800 { ++ compatible = "allwinner,sun4i-i2c"; ++ reg = <0x01c2b800 0x400>; ++ interrupts = <0 88 1>; ++ clocks = <&apb1_gates 3>; ++ clock-frequency = <100000>; ++ status = "disabled"; ++ }; ++ ++ i2c4: i2c@01c2bc00 { ++ compatible = "allwinner,sun4i-i2c"; ++ reg = <0x01c2bc00 0x400>; ++ interrupts = <0 89 1>; ++ clocks = <&apb1_gates 15>; ++ clock-frequency = <100000>; ++ status = "disabled"; ++ }; ++ + gic: interrupt-controller@01c81000 { + compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic"; + reg = <0x01c81000 0x1000>, +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/131-sun7i-add-i2c-pinmuxing.patch b/target/linux/sunxi/patches-3.12/131-sun7i-add-i2c-pinmuxing.patch new file mode 100644 index 0000000000..951059f446 --- /dev/null +++ b/target/linux/sunxi/patches-3.12/131-sun7i-add-i2c-pinmuxing.patch @@ -0,0 +1,49 @@ +From 1baebecc2892567373f5f9c3650d21496125af18 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Sat, 31 Aug 2013 23:08:49 +0200 +Subject: [PATCH] ARM: sun7i: Add the pin muxing options for the I2C + controllers + +The A20 boards we currently have share the same pins for the i2c +controllers they share. Add them to the DTSI. + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + arch/arm/boot/dts/sun7i-a20.dtsi | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index 0d0ee15..a6cd039 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -226,6 +226,27 @@ + allwinner,pull = <0>; + }; + ++ i2c0_pins_a: i2c0@0 { ++ allwinner,pins = "PB0", "PB1"; ++ allwinner,function = "i2c0"; ++ allwinner,drive = <0>; ++ allwinner,pull = <0>; ++ }; ++ ++ i2c1_pins_a: i2c1@0 { ++ allwinner,pins = "PB18", "PB19"; ++ allwinner,function = "i2c1"; ++ allwinner,drive = <0>; ++ allwinner,pull = <0>; ++ }; ++ ++ i2c2_pins_a: i2c2@0 { ++ allwinner,pins = "PB20", "PB21"; ++ allwinner,function = "i2c2"; ++ allwinner,drive = <0>; ++ allwinner,pull = <0>; ++ }; ++ + emac_pins_a: emac0@0 { + allwinner,pins = "PA0", "PA1", "PA2", + "PA3", "PA4", "PA5", "PA6", +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/132-add-dt-i2c-for-olinuxino-a20.patch b/target/linux/sunxi/patches-3.12/132-add-dt-i2c-for-olinuxino-a20.patch new file mode 100644 index 0000000000..c1f3b7097c --- /dev/null +++ b/target/linux/sunxi/patches-3.12/132-add-dt-i2c-for-olinuxino-a20.patch @@ -0,0 +1,45 @@ +From 45cfefedb2886fac4a7f18c1720310ea9792ea4c Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Sat, 31 Aug 2013 23:14:19 +0200 +Subject: [PATCH] ARM: sun7i: olinuxino-micro: Enable the I2C controllers + +The A20-olinuxino-micro uses the first three I2C controllers found on +the A20. Enable them in the DT. + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts +index 9e77855..ead3013 100644 +--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts ++++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts +@@ -60,6 +60,24 @@ + pinctrl-0 = <&uart7_pins_a>; + status = "okay"; + }; ++ ++ i2c0: i2c@01c2ac00 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c0_pins_a>; ++ status = "okay"; ++ }; ++ ++ i2c1: i2c@01c2b000 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c1_pins_a>; ++ status = "okay"; ++ }; ++ ++ i2c2: i2c@01c2b400 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c2_pins_a>; ++ status = "okay"; ++ }; + }; + + leds { +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/140-add-a31-reset-driver.patch b/target/linux/sunxi/patches-3.12/140-add-a31-reset-driver.patch new file mode 100644 index 0000000000..3d48a5fa1f --- /dev/null +++ b/target/linux/sunxi/patches-3.12/140-add-a31-reset-driver.patch @@ -0,0 +1,189 @@ +From d8d7a5805579db687fdfdfda4125b43d6a50e616 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Tue, 24 Sep 2013 11:07:43 +0300 +Subject: [PATCH] reset: Add Allwinner A31 Reset Controller Driver + +The Allwinner A31 has an IP maintaining a few other IPs in the SoC in +reset by default. Among these IPs are the High Speed Timers, hence why +we can't use the regular driver construct, and need to call the +registering function directly during machine initialisation. + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + drivers/reset/Makefile | 1 + + drivers/reset/reset-sunxi.c | 156 ++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 157 insertions(+) + create mode 100644 drivers/reset/reset-sunxi.c + +diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile +index 1e2d83f..f216b74 100644 +--- a/drivers/reset/Makefile ++++ b/drivers/reset/Makefile +@@ -1 +1,2 @@ + obj-$(CONFIG_RESET_CONTROLLER) += core.o ++obj-$(CONFIG_ARCH_SUNXI) += reset-sun6i.o +diff --git a/drivers/reset/reset-sunxi.c b/drivers/reset/reset-sunxi.c +new file mode 100644 +index 0000000..5bbd59a +--- /dev/null ++++ b/drivers/reset/reset-sunxi.c +@@ -0,0 +1,156 @@ ++/* ++ * Allwinner SoCs Reset Controller driver ++ * ++ * Copyright 2013 Maxime Ripard ++ * ++ * Maxime Ripard <maxime.ripard@free-electrons.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include <linux/err.h> ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_address.h> ++#include <linux/platform_device.h> ++#include <linux/reset-controller.h> ++#include <linux/slab.h> ++#include <linux/types.h> ++ ++struct sunxi_reset_data { ++ void __iomem *membase; ++ struct reset_controller_dev rcdev; ++}; ++ ++static int sunxi_reset_assert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ struct sunxi_reset_data *data = container_of(rcdev, ++ struct sunxi_reset_data, ++ rcdev); ++ int bank = id / BITS_PER_LONG; ++ int offset = id % BITS_PER_LONG; ++ u32 reg = readl(data->membase + (bank * 4)); ++ ++ writel(reg & ~BIT(offset), data->membase + (bank * 4)); ++ ++ return 0; ++} ++ ++static int sunxi_reset_deassert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ struct sunxi_reset_data *data = container_of(rcdev, ++ struct sunxi_reset_data, ++ rcdev); ++ int bank = id / BITS_PER_LONG; ++ int offset = id % BITS_PER_LONG; ++ u32 reg = readl(data->membase + (bank * 4)); ++ ++ writel(reg | BIT(offset), data->membase + (bank * 4)); ++ ++ return 0; ++} ++ ++static struct reset_control_ops sunxi_reset_ops = { ++ .assert = sunxi_reset_assert, ++ .deassert = sunxi_reset_deassert, ++}; ++ ++static int sunxi_reset_init(struct device_node *np) ++{ ++ struct sunxi_reset_data *data; ++ struct resource res; ++ resource_size_t size; ++ int ret; ++ ++ data = kzalloc(sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ ret = of_address_to_resource(np, 0, &res); ++ if (ret) ++ goto err_alloc; ++ ++ size = resource_size(&res); ++ data->membase = ioremap(res.start, size); ++ if (!data->membase) { ++ ret = -ENOMEM; ++ goto err_alloc; ++ } ++ ++ data->rcdev.owner = THIS_MODULE; ++ data->rcdev.nr_resets = size * 32; ++ data->rcdev.ops = &sunxi_reset_ops; ++ data->rcdev.of_node = np; ++ reset_controller_register(&data->rcdev); ++ ++ return 0; ++ ++err_alloc: ++ kfree(data); ++ return ret; ++}; ++ ++/* ++ * These are the reset controller we need to initialize early on in ++ * our system, before we can even think of using a regular device ++ * driver for it. ++ */ ++static const struct of_device_id sunxi_early_reset_dt_ids[] __initdata = { ++ { .compatible = "allwinner,sun6i-a31-ahb1-reset", }, ++ { /* sentinel */ }, ++}; ++ ++void __init sun6i_reset_init(void) ++{ ++ struct device_node *np; ++ ++ for_each_matching_node(np, sunxi_early_reset_dt_ids) ++ sunxi_reset_init(np); ++} ++ ++/* ++ * And these are the controllers we can register through the regular ++ * device model. ++ */ ++static const struct of_device_id sunxi_reset_dt_ids[] = { ++ { .compatible = "allwinner,sun4i-clock-reset", }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, sunxi_reset_dt_ids); ++ ++static int sunxi_reset_probe(struct platform_device *pdev) ++{ ++ return sunxi_reset_init(pdev->dev.of_node); ++} ++ ++static int sunxi_reset_remove(struct platform_device *pdev) ++{ ++ struct sunxi_reset_data *data = platform_get_drvdata(pdev); ++ ++ reset_controller_unregister(&data->rcdev); ++ iounmap(data->membase); ++ kfree(data); ++ ++ return 0; ++} ++ ++static struct platform_driver sunxi_reset_driver = { ++ .probe = sunxi_reset_probe, ++ .remove = sunxi_reset_remove, ++ .driver = { ++ .name = "sunxi-reset", ++ .owner = THIS_MODULE, ++ .of_match_table = sunxi_reset_dt_ids, ++ }, ++}; ++module_platform_driver(sunxi_reset_driver); ++ ++MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com"); ++MODULE_DESCRIPTION("Allwinner SoCs Reset Controller Driver"); ++MODULE_LICENSE("GPL"); +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/141-add-Kconfig-for-reset.patch b/target/linux/sunxi/patches-3.12/141-add-Kconfig-for-reset.patch new file mode 100644 index 0000000000..394b9c7330 --- /dev/null +++ b/target/linux/sunxi/patches-3.12/141-add-Kconfig-for-reset.patch @@ -0,0 +1,27 @@ +From 6bf236bb67dfabd0434df47ff1247b1310d4ccf5 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Tue, 24 Sep 2013 11:09:55 +0300 +Subject: [PATCH] ARM: sunxi: Select ARCH_HAS_RESET_CONTROLLER + +The A31 has a reset controller, and we have to select this option to +have access to the reset controller framework. + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + arch/arm/mach-sunxi/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig +index bce0d42..547004c 100644 +--- a/arch/arm/mach-sunxi/Kconfig ++++ b/arch/arm/mach-sunxi/Kconfig +@@ -1,5 +1,6 @@ + config ARCH_SUNXI + bool "Allwinner A1X SOCs" if ARCH_MULTI_V7 ++ select ARCH_HAS_RESET_CONTROLLER + select ARCH_REQUIRE_GPIOLIB + select ARM_GIC + select CLKSRC_MMIO +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/142-register-a31-reset.patch b/target/linux/sunxi/patches-3.12/142-register-a31-reset.patch new file mode 100644 index 0000000000..4853647298 --- /dev/null +++ b/target/linux/sunxi/patches-3.12/142-register-a31-reset.patch @@ -0,0 +1,41 @@ +From ba9cb86c174603252ee5b5f2b277dab46a99cf02 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Sat, 5 Oct 2013 14:53:48 +0200 +Subject: [PATCH] ARM: sunxi: Register the A31 reset IP in init_time + +The A31 has a reset IP that maintains a few other IPs in reset by +default. Among these IPs are the UARTs, and most notably the timers. We +thus need to register the reset driver before initializing the timers so +that the reset timer can use the reset framework. + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + arch/arm/mach-sunxi/sunxi.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c +index f184f6c..2e79736 100644 +--- a/arch/arm/mach-sunxi/sunxi.c ++++ b/arch/arm/mach-sunxi/sunxi.c +@@ -142,9 +142,17 @@ static void __init sunxi_dt_init(void) + NULL, + }; + ++extern void __init sun6i_reset_init(void); ++static void __init sun6i_timer_init(void) ++{ ++ sunxi_init_clocks(); ++ sun6i_reset_init(); ++ clocksource_of_init(); ++} ++ + DT_MACHINE_START(SUN6I_DT, "Allwinner sun6i (A31) Family") + .init_machine = sunxi_dt_init, +- .init_time = sunxi_timer_init, ++ .init_time = sun6i_timer_init, + .dt_compat = sun6i_board_dt_compat, + .restart = sun6i_restart, + MACHINE_END +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/143-add-dtsi-for-reset.patch b/target/linux/sunxi/patches-3.12/143-add-dtsi-for-reset.patch new file mode 100644 index 0000000000..62ade3651e --- /dev/null +++ b/target/linux/sunxi/patches-3.12/143-add-dtsi-for-reset.patch @@ -0,0 +1,94 @@ +From 2a906d06b21968803ce504348864908ad1ed66ac Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Tue, 24 Sep 2013 11:10:41 +0300 +Subject: [PATCH] ARM: sun6i: Add the reset controller to the DTSI + +The A31 has a reset controller IP that maintains a few other IPs in +reset, among which we can find the UARTs, high speed timers or the I2C. +Now that we have support for them, add the reset controllers to the DTSI. + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + arch/arm/boot/dts/sun6i-a31.dtsi | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi +index c1751a6..c7e0658 100644 +--- a/arch/arm/boot/dts/sun6i-a31.dtsi ++++ b/arch/arm/boot/dts/sun6i-a31.dtsi +@@ -209,6 +209,24 @@ + }; + }; + ++ ahb1_rst: reset@01c202c0 { ++ #reset-cells = <1>; ++ compatible = "allwinner,sun6i-a31-ahb1-reset"; ++ reg = <0x01c202c0 0xc>; ++ }; ++ ++ apb1_rst: reset@01c202d0 { ++ #reset-cells = <1>; ++ compatible = "allwinner,sun4i-clock-reset"; ++ reg = <0x01c202d0 0x4>; ++ }; ++ ++ apb2_rst: reset@01c202d8 { ++ #reset-cells = <1>; ++ compatible = "allwinner,sun4i-clock-reset"; ++ reg = <0x01c202d8 0x4>; ++ }; ++ + timer@01c20c00 { + compatible = "allwinner,sun4i-timer"; + reg = <0x01c20c00 0xa0>; +@@ -232,6 +250,7 @@ + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&apb2_gates 16>; ++ resets = <&apb2_rst 16>; + status = "disabled"; + }; + +@@ -242,6 +261,7 @@ + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&apb2_gates 17>; ++ resets = <&apb2_rst 17>; + status = "disabled"; + }; + +@@ -252,6 +272,7 @@ + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&apb2_gates 18>; ++ resets = <&apb2_rst 18>; + status = "disabled"; + }; + +@@ -262,6 +283,7 @@ + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&apb2_gates 19>; ++ resets = <&apb2_rst 19>; + status = "disabled"; + }; + +@@ -272,6 +294,7 @@ + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&apb2_gates 20>; ++ resets = <&apb2_rst 20>; + status = "disabled"; + }; + +@@ -282,6 +305,7 @@ + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&apb2_gates 21>; ++ resets = <&apb2_rst 21>; + status = "disabled"; + }; + +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/145-fix-reset-for-all-sunxi.patch b/target/linux/sunxi/patches-3.12/145-fix-reset-for-all-sunxi.patch new file mode 100644 index 0000000000..130bf04e23 --- /dev/null +++ b/target/linux/sunxi/patches-3.12/145-fix-reset-for-all-sunxi.patch @@ -0,0 +1,20 @@ +From ab2f1e0056db0e5a0717981546a69d5b81439661 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Sun, 20 Oct 2013 22:59:01 +0200 +Subject: [PATCH] reset: Fix mpripard's reset patch + +--- + drivers/reset/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile +index f216b74..cc29832 100644 +--- a/drivers/reset/Makefile ++++ b/drivers/reset/Makefile +@@ -1,2 +1,2 @@ + obj-$(CONFIG_RESET_CONTROLLER) += core.o +-obj-$(CONFIG_ARCH_SUNXI) += reset-sun6i.o ++obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/150-sun4i-add-dt-bindings.patch b/target/linux/sunxi/patches-3.12/150-sun4i-add-dt-bindings.patch new file mode 100644 index 0000000000..3bc67698bb --- /dev/null +++ b/target/linux/sunxi/patches-3.12/150-sun4i-add-dt-bindings.patch @@ -0,0 +1,31 @@ +From 378dab1f11d0386e26363517922dc086227aa6c5 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Thu, 19 Sep 2013 21:58:47 +0200 +Subject: [PATCH] ARM: sun4i: dt: Add bindings for USB clocks + +--- + arch/arm/boot/dts/sun4i-a10.dtsi | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi +index 5e2fc45..3033684 100644 +--- a/arch/arm/boot/dts/sun4i-a10.dtsi ++++ b/arch/arm/boot/dts/sun4i-a10.dtsi +@@ -89,6 +89,14 @@ + clock-output-names = "pll6_sata", "pll6_other", "pll6"; + }; + ++ usb:usb@0x01c200cc { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun47i-usb-gates-clk"; ++ reg = <0x01c200cc 0x4>; ++ clocks = <&pll6 1>; ++ clock-output-names = "usb_ohci0", "usb_ohci1", "usb_phy"; ++ }; ++ + /* dummy is 200M */ + cpu: cpu@01c20054 { + #clock-cells = <0>; +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/151-clk-sunxi-add-usbclocks.patch b/target/linux/sunxi/patches-3.12/151-clk-sunxi-add-usbclocks.patch new file mode 100644 index 0000000000..2fb52f16aa --- /dev/null +++ b/target/linux/sunxi/patches-3.12/151-clk-sunxi-add-usbclocks.patch @@ -0,0 +1,35 @@ +From 43c2d3189567342f68ec192f2eeab6ae4c4d1ddf Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Thu, 19 Sep 2013 21:59:32 +0200 +Subject: [PATCH] clk: sunxi: Add support for USB clocks + +--- + drivers/clk/sunxi/clk-sunxi.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c +index 96c01b2..cbe1516 100644 +--- a/drivers/clk/sunxi/clk-sunxi.c ++++ b/drivers/clk/sunxi/clk-sunxi.c +@@ -619,6 +619,10 @@ struct gates_data { + .mask = {0x7F77FFF, 0x14FB3F}, + }; + ++static const struct gates_data sun47i_usb_gates_data __initconst = { ++ .mask = {0x1C0}, ++}; ++ + static const struct gates_data sun5i_a10s_ahb_gates_data __initconst = { + .mask = {0x147667e7, 0x185915}, + }; +@@ -867,6 +871,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node, + static const struct of_device_id clk_gates_match[] __initconst = { + {.compatible = "allwinner,sun4i-axi-gates-clk", .data = &sun4i_axi_gates_data,}, + {.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &sun4i_ahb_gates_data,}, ++ {.compatible = "allwinner,sun47i-usb-gates-clk", .data = &sun47i_usb_gates_data,}, + {.compatible = "allwinner,sun5i-a10s-ahb-gates-clk", .data = &sun5i_a10s_ahb_gates_data,}, + {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,}, + {.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,}, +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/152-sun4i-dt-add-usb-ehci-bindings.patch b/target/linux/sunxi/patches-3.12/152-sun4i-dt-add-usb-ehci-bindings.patch new file mode 100644 index 0000000000..0a46d068d8 --- /dev/null +++ b/target/linux/sunxi/patches-3.12/152-sun4i-dt-add-usb-ehci-bindings.patch @@ -0,0 +1,62 @@ +From 90bc2022b61dcfd4d785416ee3aabc2157bfd57a Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Wed, 18 Sep 2013 00:30:04 +0200 +Subject: [PATCH] ARM: sun4i: dt: Add USB EHCI bindings + +--- + arch/arm/boot/dts/sun4i-a10.dtsi | 33 +++++++++++++++++++++++++++++++++ + 1 file changed, 33 insertions(+) + +diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi +index 3033684..6c05264 100644 +--- a/arch/arm/boot/dts/sun4i-a10.dtsi ++++ b/arch/arm/boot/dts/sun4i-a10.dtsi +@@ -15,6 +15,11 @@ + / { + interrupt-parent = <&intc>; + ++ aliases { ++ ehci1 = &ehci0; ++ ehci2 = &ehci1; ++ }; ++ + cpus { + #address-cells = <1>; + #size-cells = <0>; +@@ -407,5 +412,33 @@ + clock-frequency = <100000>; + status = "disabled"; + }; ++ ++ usb_rst: reset@0x01c200cc { ++ #reset-cells = <1>; ++ compatible = "allwinner,sun4i-clock-reset"; ++ reg = <0x01c200cc 0x4>; ++ }; ++ ++ ehci0: ehci0@0x01c14000 { ++ compatible = "allwinner,sunxi-ehci"; ++ reg = <0x01c14000 0x400 0x01c14800 0x4 0x01c13404 0x4>; ++ interrupts = <39>; ++ resets = <&usb_rst 1>; ++ reset-names = "ehci_reset"; ++ clocks = <&usb 8>, <&ahb_gates 1>; ++ clock-names = "usb_phy", "ahb_ehci"; ++ status = "disabled"; ++ }; ++ ++ ehci1: ehci1@0x01c1c000 { ++ compatible = "allwinner,sunxi-ehci"; ++ reg = <0x01c1c000 0x400 0x01c1c800 0x4 0x01c13404 0x4>; ++ interrupts = <40>; ++ resets = <&usb_rst 2>; ++ reset-names = "ehci_reset"; ++ clocks = <&usb 8>, <&ahb_gates 3>; ++ clock-names = "usb_phy", "ahb_ehci"; ++ status = "disabled"; ++ }; + }; + }; +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/153-add-sunxi-ehci.patch b/target/linux/sunxi/patches-3.12/153-add-sunxi-ehci.patch new file mode 100644 index 0000000000..8a78c2d54b --- /dev/null +++ b/target/linux/sunxi/patches-3.12/153-add-sunxi-ehci.patch @@ -0,0 +1,499 @@ +From b84d49247eb062672a56ce15f1c08f792099de97 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Wed, 18 Sep 2013 21:45:03 +0200 +Subject: [PATCH] ARM: sunxi: usb: Add Allwinner sunXi EHCI driver + +--- + drivers/usb/host/Kconfig | 9 + + drivers/usb/host/Makefile | 1 + + drivers/usb/host/ehci-sunxi.c | 446 ++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 456 insertions(+) + create mode 100644 drivers/usb/host/ehci-sunxi.c + +diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig +index b3f20d7..ecc2745 100644 +--- a/drivers/usb/host/Kconfig ++++ b/drivers/usb/host/Kconfig +@@ -274,6 +274,15 @@ config USB_OCTEON_EHCI + USB 2.0 device support. All CN6XXX based chips with USB are + supported. + ++config USB_SUNXI_EHCI ++ tristate "Allwinner sunXi EHCI support" ++ depends on ARCH_SUNXI ++ default n ++ help ++ Enable support for the Allwinner sunXi on-chip EHCI ++ controller. It is needed for high-speed (480Mbit/sec) ++ USB 2.0 device support. ++ + endif # USB_EHCI_HCD + + config USB_OXU210HP_HCD +diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile +index 50b0041..d2e2c8c 100644 +--- a/drivers/usb/host/Makefile ++++ b/drivers/usb/host/Makefile +@@ -38,6 +38,7 @@ obj-$(CONFIG_USB_EHCI_S5P) += ehci-s5p.o + obj-$(CONFIG_USB_EHCI_HCD_AT91) += ehci-atmel.o + obj-$(CONFIG_USB_EHCI_MSM) += ehci-msm.o + obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o ++obj-$(CONFIG_USB_SUNXI_EHCI) += ehci-sunxi.o + + obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o + obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o +diff --git a/drivers/usb/host/ehci-sunxi.c b/drivers/usb/host/ehci-sunxi.c +new file mode 100644 +index 0000000..e7e15cc +--- /dev/null ++++ b/drivers/usb/host/ehci-sunxi.c +@@ -0,0 +1,446 @@ ++/* ++ * Copyright (C) 2013 Roman Byshko ++ * ++ * Roman Byshko <rbyshko@gmail.com> ++ * ++ * Based on code from ++ * Allwinner Technology Co., Ltd. <www.allwinnertech.com> ++ * ++ * 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 <linux/bitops.h> ++#include <linux/clk.h> ++#include <linux/dma-mapping.h> ++#include <linux/io.h> ++#include <linux/irq.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/platform_device.h> ++#include <linux/regulator/consumer.h> ++#include <linux/reset.h> ++#include <linux/usb.h> ++#include <linux/usb/hcd.h> ++ ++#include "ehci.h" ++ ++#define DRV_DESC "Allwinner sunXi EHCI driver" ++#define DRV_NAME "sunxi-ehci" ++ ++#define SUNXI_USB_PASSBY_EN 1 ++ ++#define SUNXI_EHCI_AHB_ICHR8_EN BIT(10) ++#define SUNXI_EHCI_AHB_INCR4_BURST_EN BIT(9) ++#define SUNXI_EHCI_AHB_INCRX_ALIGN_EN BIT(8) ++#define SUNXI_EHCI_ULPI_BYPASS_EN BIT(0) ++ ++struct sunxi_ehci_hcd { ++ struct clk *phy_clk; ++ struct clk *ahb_ehci_clk; ++ struct reset_control *reset; ++ struct regulator *vbus_reg; ++ void __iomem *csr; ++ void __iomem *pmuirq; ++ int irq; ++ int id; ++}; ++ ++ ++static void usb_phy_write(struct sunxi_ehci_hcd *sunxi_ehci,u32 addr, u32 data, u32 len) ++{ ++ u32 j = 0; ++ u32 temp = 0; ++ u32 usbc_bit = 0; ++ void __iomem *dest = sunxi_ehci->csr; ++ ++ usbc_bit = BIT(sunxi_ehci->id << 1); ++ ++ for (j = 0; j < len; j++) { ++ temp = readl(dest); ++ ++ /* clear the address portion */ ++ temp &= ~(0xff << 8); ++ ++ /* set the address */ ++ temp |= ((addr + j) << 8); ++ writel(temp, dest); ++ ++ /* set the data bit and clear usbc bit*/ ++ temp = readb(dest); ++ if (data & 0x1) ++ temp |= BIT(7); ++ else ++ temp &= ~BIT(7); ++ temp &= ~usbc_bit; ++ writeb(temp, dest); ++ ++ /* flip usbc_bit */ ++ __set_bit(usbc_bit, dest); ++ __clear_bit(usbc_bit, dest); ++ ++ data >>= 1; ++ } ++} ++ ++/* FIXME: should this function be protected by a lock? ++ * ehci1 and ehci0 could call it concurrently with same csr. ++ */ ++static void sunxi_usb_phy_init(struct sunxi_ehci_hcd *sunxi_ehci) ++{ ++ /* The following comments are machine ++ * translated from Chinese, you have been warned! ++ */ ++ ++ /* adjust PHY's magnitude and rate */ ++ usb_phy_write(sunxi_ehci, 0x20, 0x14, 5); ++ ++ /* threshold adjustment disconnect */ ++ usb_phy_write(sunxi_ehci, 0x2a, 3, 2); ++ ++ return; ++} ++ ++static void sunxi_usb_passby(struct sunxi_ehci_hcd *sunxi_ehci, int enable) ++{ ++ unsigned long reg_value = 0; ++ unsigned long bits = 0; ++ static DEFINE_SPINLOCK(lock); ++ unsigned long flags = 0; ++ void __iomem *addr = sunxi_ehci->pmuirq; ++ ++ bits = SUNXI_EHCI_AHB_ICHR8_EN | ++ SUNXI_EHCI_AHB_INCR4_BURST_EN | ++ SUNXI_EHCI_AHB_INCRX_ALIGN_EN | ++ SUNXI_EHCI_ULPI_BYPASS_EN; ++ ++ spin_lock_irqsave(&lock, flags); ++ ++ reg_value = readl(addr); ++ ++ if (enable) ++ reg_value |= bits; ++ else ++ reg_value &= ~bits; ++ ++ writel(reg_value, addr); ++ ++ spin_unlock_irqrestore(&lock, flags); ++ ++ return; ++} ++ ++static void sunxi_ehci_disable(struct sunxi_ehci_hcd *sunxi_ehci) ++{ ++ regulator_disable(sunxi_ehci->vbus_reg); ++ ++ sunxi_usb_passby(sunxi_ehci, !SUNXI_USB_PASSBY_EN); ++ ++ clk_disable_unprepare(sunxi_ehci->ahb_ehci_clk); ++ clk_disable_unprepare(sunxi_ehci->phy_clk); ++ ++ reset_control_assert(sunxi_ehci->reset); ++} ++ ++static int sunxi_ehci_enable(struct sunxi_ehci_hcd *sunxi_ehci) ++{ ++ int ret; ++ ++ ret = clk_prepare_enable(sunxi_ehci->phy_clk); ++ if (ret) ++ return ret; ++ ++ ret = reset_control_deassert(sunxi_ehci->reset); ++ if (ret) ++ goto fail1; ++ ++ ret = clk_prepare_enable(sunxi_ehci->ahb_ehci_clk); ++ if (ret) ++ goto fail2; ++ ++ sunxi_usb_phy_init(sunxi_ehci); ++ ++ sunxi_usb_passby(sunxi_ehci, SUNXI_USB_PASSBY_EN); ++ ++ ret = regulator_enable(sunxi_ehci->vbus_reg); ++ if (ret) ++ goto fail3; ++ ++ return 0; ++ ++fail3: ++ clk_disable_unprepare(sunxi_ehci->ahb_ehci_clk); ++fail2: ++ reset_control_assert(sunxi_ehci->reset); ++fail1: ++ clk_disable_unprepare(sunxi_ehci->phy_clk); ++ ++ return ret; ++} ++ ++#ifdef CONFIG_PM ++static int sunxi_ehci_suspend(struct device *dev) ++{ ++ struct sunxi_ehci_hcd *sunxi_ehci = NULL; ++ struct usb_hcd *hcd = dev_get_drvdata(dev); ++ int ret; ++ ++ bool do_wakeup = device_may_wakeup(dev); ++ ++ ret = ehci_suspend(hcd, do_wakeup); ++ ++ sunxi_ehci = (struct sunxi_ehci_hcd *)hcd_to_ehci(hcd)->priv; ++ ++ sunxi_ehci_disable(sunxi_ehci); ++ ++ return ret; ++} ++ ++static int sunxi_ehci_resume(struct device *dev) ++{ ++ struct sunxi_ehci_hcd *sunxi_ehci = NULL; ++ struct usb_hcd *hcd = dev_get_drvdata(dev); ++ int ret; ++ ++ sunxi_ehci = (struct sunxi_ehci_hcd *)hcd_to_ehci(hcd)->priv; ++ ++ ret = sunxi_ehci_enable(sunxi_ehci); ++ if (ret) ++ return ret; ++ ++ return ehci_resume(hcd, false); ++} ++ ++ ++static const struct dev_pm_ops sunxi_ehci_pmops = { ++ .suspend = sunxi_ehci_suspend, ++ .resume = sunxi_ehci_resume, ++}; ++ ++#define SUNXI_EHCI_PMOPS (&sunxi_ehci_pmops) ++#else /* !CONFIG_PM */ ++#define SUNXI_EHCI_PMOPS NULL ++#endif /* CONFIG_PM */ ++ ++static const struct ehci_driver_overrides sunxi_overrides __initconst = { ++ .reset = NULL, ++ .extra_priv_size = sizeof(struct sunxi_ehci_hcd), ++}; ++ ++/* FIXME: Should there be two instances of hc_driver, ++ * or one is enough to handle two EHCI controllers? */ ++static struct hc_driver __read_mostly sunxi_ehci_hc_driver; ++ ++static int sunxi_ehci_init(struct platform_device *pdev, struct usb_hcd *hcd, ++ struct sunxi_ehci_hcd *sunxi_ehci) ++{ ++ void __iomem *ehci_regs = NULL; ++ struct resource *res = NULL; ++ ++ sunxi_ehci->vbus_reg = devm_regulator_get(&pdev->dev, "vbus"); ++ if (IS_ERR(sunxi_ehci->vbus_reg)) { ++ if (PTR_ERR(sunxi_ehci->vbus_reg) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; ++ ++ dev_info(&pdev->dev, "no USB VBUS power supply found\n"); ++ } ++ ++ sunxi_ehci->id = of_alias_get_id(pdev->dev.of_node, "ehci"); ++ if (sunxi_ehci->id < 0) ++ return sunxi_ehci->id; ++ ++ /* FIXME: should res be freed on some failure? */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "failed to get I/O memory\n"); ++ return -ENXIO; ++ } ++ ehci_regs = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(ehci_regs)) ++ return PTR_ERR(ehci_regs); ++ ++ hcd->rsrc_start = res->start; ++ hcd->rsrc_len = resource_size(res); ++ hcd->regs = ehci_regs; ++ hcd_to_ehci(hcd)->caps = ehci_regs; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ if (!res) { ++ dev_err(&pdev->dev, "failed to get I/O memory\n"); ++ return -ENXIO; ++ } ++ sunxi_ehci->pmuirq = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(sunxi_ehci->pmuirq)) ++ return PTR_ERR(sunxi_ehci->pmuirq); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 2); ++ if (!res) { ++ dev_err(&pdev->dev, "failed to get I/O memory\n"); ++ return -ENXIO; ++ } ++ ++ /* FIXME: this one byte needs to be shared between both EHCIs, ++ * that is why ioremap instead of devm_ioremap_resource, ++ * memory is not unmaped back for now. ++ */ ++ sunxi_ehci->csr = ioremap(res->start, resource_size(res)); ++ if (IS_ERR(sunxi_ehci->csr)) { ++ dev_err(&pdev->dev, "failed to remap memory\n"); ++ return PTR_ERR(sunxi_ehci->csr); ++ } ++ ++ sunxi_ehci->irq = platform_get_irq(pdev, 0); ++ if (!sunxi_ehci->irq) { ++ dev_err(&pdev->dev, "failed to get IRQ\n"); ++ return -ENODEV; ++ } ++ ++ sunxi_ehci->phy_clk = devm_clk_get(&pdev->dev, "usb_phy"); ++ if (IS_ERR(sunxi_ehci->phy_clk)) { ++ dev_err(&pdev->dev, "failed to get usb_phy clock\n"); ++ return PTR_ERR(sunxi_ehci->phy_clk); ++ } ++ sunxi_ehci->ahb_ehci_clk = devm_clk_get(&pdev->dev, "ahb_ehci"); ++ if (IS_ERR(sunxi_ehci->ahb_ehci_clk)) { ++ dev_err(&pdev->dev, "failed to get ahb_ehci clock\n"); ++ return PTR_ERR(sunxi_ehci->ahb_ehci_clk); ++ } ++ ++ sunxi_ehci->reset = reset_control_get(&pdev->dev, "ehci_reset"); ++ if (IS_ERR(sunxi_ehci->reset)) ++ { ++ dev_err(&pdev->dev, "failed to get ehci_reset reset line\n"); ++ return PTR_ERR(sunxi_ehci->reset); ++ } ++ ++ return 0; ++} ++ ++static int sunxi_ehci_probe(struct platform_device *pdev) ++{ ++ struct sunxi_ehci_hcd *sunxi_ehci = NULL; ++ struct usb_hcd *hcd = NULL; ++ int ret; ++ ++ if (pdev->num_resources != 4) { ++ dev_err(&pdev->dev, "invalid number of resources: %i\n", ++ pdev->num_resources); ++ return -ENODEV; ++ } ++ ++ if (pdev->resource[0].flags != IORESOURCE_MEM ++ || pdev->resource[1].flags != IORESOURCE_MEM ++ || pdev->resource[2].flags != IORESOURCE_MEM ++ || pdev->resource[3].flags != IORESOURCE_IRQ) { ++ dev_err(&pdev->dev, "invalid resource type\n"); ++ return -ENODEV; ++ } ++ ++ if (!pdev->dev.dma_mask) ++ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; ++ if (!pdev->dev.coherent_dma_mask) ++ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); ++ ++ hcd = usb_create_hcd(&sunxi_ehci_hc_driver, &pdev->dev, ++ dev_name(&pdev->dev)); ++ if (!hcd) { ++ dev_err(&pdev->dev, "unable to create HCD\n"); ++ return -ENOMEM; ++ } ++ ++ platform_set_drvdata(pdev, hcd); ++ ++ sunxi_ehci = (struct sunxi_ehci_hcd *)hcd_to_ehci(hcd)->priv; ++ ret = sunxi_ehci_init(pdev, hcd, sunxi_ehci); ++ if (ret) ++ goto fail1; ++ ++ ret = sunxi_ehci_enable(sunxi_ehci); ++ if (ret) ++ goto fail1; ++ ++ ret = usb_add_hcd(hcd, sunxi_ehci->irq, IRQF_SHARED | IRQF_DISABLED); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to add USB HCD\n"); ++ goto fail2; ++ } ++ ++ return 0; ++ ++fail2: ++ sunxi_ehci_disable(sunxi_ehci); ++ ++fail1: ++ usb_put_hcd(hcd); ++ return ret; ++} ++ ++static int sunxi_ehci_remove(struct platform_device *pdev) ++{ ++ struct usb_hcd *hcd = platform_get_drvdata(pdev); ++ struct sunxi_ehci_hcd *sunxi_ehci = NULL; ++ ++ sunxi_ehci = (struct sunxi_ehci_hcd *)hcd_to_ehci(hcd)->priv; ++ ++ usb_remove_hcd(hcd); ++ ++ sunxi_ehci_disable(sunxi_ehci); ++ ++ usb_put_hcd(hcd); ++ ++ return 0; ++} ++ ++static void sunxi_ehci_shutdown(struct platform_device *pdev) ++{ ++ struct usb_hcd *hcd = platform_get_drvdata(pdev); ++ struct sunxi_ehci_hcd *sunxi_ehci = NULL; ++ ++ sunxi_ehci = (struct sunxi_ehci_hcd *)hcd_to_ehci(hcd)->priv; ++ ++ usb_hcd_platform_shutdown(pdev); ++ ++ sunxi_ehci_disable(sunxi_ehci); ++} ++ ++static const struct of_device_id ehci_of_match[] = { ++ {.compatible = "allwinner,sunxi-ehci"}, ++ {}, ++}; ++ ++static struct platform_driver ehci_sunxi_driver = { ++ .driver = { ++ .of_match_table = ehci_of_match, ++ .name = DRV_NAME, ++ .pm = SUNXI_EHCI_PMOPS, ++ }, ++ .probe = sunxi_ehci_probe, ++ .remove = sunxi_ehci_remove, ++ .shutdown = sunxi_ehci_shutdown, ++}; ++ ++static int __init sunxi_ehci_init_module(void) ++{ ++ if (usb_disabled()) ++ return -ENODEV; ++ ++ pr_info(DRV_NAME ": " DRV_DESC "\n"); ++ ++ ehci_init_driver(&sunxi_ehci_hc_driver, &sunxi_overrides); ++ ++ return platform_driver_register(&ehci_sunxi_driver); ++} ++module_init(sunxi_ehci_init_module); ++ ++static void __exit sunxi_ehci_exit_module(void) ++{ ++ platform_driver_unregister(&ehci_sunxi_driver); ++} ++module_exit(sunxi_ehci_exit_module); ++ ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:" DRV_NAME); ++MODULE_DEVICE_TABLE(of, ehci_of_match); ++MODULE_AUTHOR("Roman Byshko <rbyshko@gmail.com>"); +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/154-add-ehci-for-a1000.patch b/target/linux/sunxi/patches-3.12/154-add-ehci-for-a1000.patch new file mode 100644 index 0000000000..dee5b1b38e --- /dev/null +++ b/target/linux/sunxi/patches-3.12/154-add-ehci-for-a1000.patch @@ -0,0 +1,82 @@ +From bc8138b4218307a8f25076ec5c8c1eae1e5e8d78 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Wed, 18 Sep 2013 00:30:40 +0200 +Subject: [PATCH] ARM: sun4i: dt: Add EHCI bindings to the Mele A1000 + +--- + arch/arm/boot/dts/sun4i-a10-a1000.dts | 46 +++++++++++++++++++++++++++++++++++ + 1 file changed, 46 insertions(+) + +diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts +index eb4d73b..68c705d 100644 +--- a/arch/arm/boot/dts/sun4i-a10-a1000.dts ++++ b/arch/arm/boot/dts/sun4i-a10-a1000.dts +@@ -53,6 +53,20 @@ + allwinner,drive = <0>; + allwinner,pull = <0>; + }; ++ ++ usb1_vbus_pin: usb1_vbus_pin@0 { ++ allwinner,pins = "PH6"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <2>; ++ }; ++ ++ usb2_vbus_pin: usb2_vbus_pin@0 { ++ allwinner,pins = "PH3"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <2>; ++ }; + }; + + uart0: serial@01c28000 { +@@ -66,6 +80,16 @@ + pinctrl-0 = <&i2c0_pins_a>; + status = "okay"; + }; ++ ++ ehci0: ehci0@0x01c14000 { ++ vbus-supply = <®_usb1_vbus>; ++ status = "okay"; ++ }; ++ ++ ehci1: ehci1@0x01c1c000 { ++ vbus-supply = <®_usb2_vbus>; ++ status = "okay"; ++ }; + }; + + leds { +@@ -97,5 +121,27 @@ + enable-active-high; + gpio = <&pio 7 15 0>; + }; ++ ++ reg_usb1_vbus: usb1-vbus { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb1_vbus_pin>; ++ regulator-name = "usb1-vbus"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ enable-active-high; ++ gpio = <&pio 7 6 0>; ++ }; ++ ++ reg_usb2_vbus: usb2-vbus { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb2_vbus_pin>; ++ regulator-name = "usb2-vbus"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ enable-active-high; ++ gpio = <&pio 7 3 0>; ++ }; + }; + }; +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/155-add-ehci-for-cubieboard-a10.patch b/target/linux/sunxi/patches-3.12/155-add-ehci-for-cubieboard-a10.patch new file mode 100644 index 0000000000..2cb98ae5ff --- /dev/null +++ b/target/linux/sunxi/patches-3.12/155-add-ehci-for-cubieboard-a10.patch @@ -0,0 +1,85 @@ +From bf96cf461ca2d36e962a4acf83f6f779a05c7df3 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Wed, 18 Sep 2013 22:45:06 +0200 +Subject: [PATCH] ARM: sun4i: dt: Add EHCI bindings to Cubieboard-A10 + +--- + arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 50 ++++++++++++++++++++++++++++++ + 1 file changed, 50 insertions(+) + +diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts +index 425a7db..eb6c3c1 100644 +--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts ++++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts +@@ -49,6 +49,20 @@ + allwinner,drive = <1>; + allwinner,pull = <0>; + }; ++ ++ usb1_vbus_pin: usb1_vbus_pin@0 { ++ allwinner,pins = "PH6"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <2>; ++ }; ++ ++ usb2_vbus_pin: usb2_vbus_pin@0 { ++ allwinner,pins = "PH3"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <2>; ++ }; + }; + + uart0: serial@01c28000 { +@@ -68,6 +82,16 @@ + pinctrl-0 = <&i2c1_pins_a>; + status = "okay"; + }; ++ ++ ehci0: ehci0@0x01c14000 { ++ vbus-supply = <®_usb1_vbus>; ++ status = "okay"; ++ }; ++ ++ ehci1: ehci1@0x01c1c000 { ++ vbus-supply = <®_usb2_vbus>; ++ status = "okay"; ++ }; + }; + + leds { +@@ -86,4 +110,30 @@ + linux,default-trigger = "heartbeat"; + }; + }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ ++ reg_usb1_vbus: usb1-vbus { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb1_vbus_pin>; ++ regulator-name = "usb1-vbus"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ enable-active-high; ++ gpio = <&pio 7 6 0>; ++ }; ++ ++ reg_usb2_vbus: usb2-vbus { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb2_vbus_pin>; ++ regulator-name = "usb2-vbus"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ enable-active-high; ++ gpio = <&pio 7 3 0>; ++ }; ++ }; + }; +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/156-sun7i-add-dt-bindings-for-usbclocks.patch b/target/linux/sunxi/patches-3.12/156-sun7i-add-dt-bindings-for-usbclocks.patch new file mode 100644 index 0000000000..5dfbc5e6c6 --- /dev/null +++ b/target/linux/sunxi/patches-3.12/156-sun7i-add-dt-bindings-for-usbclocks.patch @@ -0,0 +1,31 @@ +From 336d23a348d6595cac9a282616e983dddb7c7600 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Thu, 19 Sep 2013 21:24:20 +0200 +Subject: [PATCH] ARM: sun7i: dt: Add bindings for USB clocks + +--- + arch/arm/boot/dts/sun7i-a20.dtsi | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index 81e6e74..4fe484c 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -85,6 +85,14 @@ + clock-output-names = "pll6_sata", "pll6_other", "pll6"; + }; + ++ usb:usb@0x01c200cc { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun47i-usb-gates-clk"; ++ reg = <0x01c200cc 0x4>; ++ clocks = <&pll6 1>; ++ clock-output-names = "usb_ohci0", "usb_ohci1", "usb_phy"; ++ }; ++ + cpu: cpu@01c20054 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-cpu-clk"; +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/157-sun7i-add-dt-usb-ehci-bindings.patch b/target/linux/sunxi/patches-3.12/157-sun7i-add-dt-usb-ehci-bindings.patch new file mode 100644 index 0000000000..db7905f9b0 --- /dev/null +++ b/target/linux/sunxi/patches-3.12/157-sun7i-add-dt-usb-ehci-bindings.patch @@ -0,0 +1,62 @@ +From b434c5aa38e2db0fff9fa39c6e47cc9d13afe8e1 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Thu, 19 Sep 2013 21:36:10 +0200 +Subject: [PATCH] ARM: sun7i: dt: Add USB EHCI bindings + +--- + arch/arm/boot/dts/sun7i-a20.dtsi | 33 +++++++++++++++++++++++++++++++++ + 1 file changed, 33 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index 4fe484c..b4e4a5a 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -16,6 +16,11 @@ + / { + interrupt-parent = <&gic>; + ++ aliases { ++ ehci1 = &ehci0; ++ ehci2 = &ehci1; ++ }; ++ + cpus { + #address-cells = <1>; + #size-cells = <0>; +@@ -434,5 +439,33 @@ + #interrupt-cells = <3>; + interrupts = <1 9 0xf04>; + }; ++ ++ usb_rst: reset@0x01c200cc { ++ #reset-cells = <1>; ++ compatible = "allwinner,sun4i-clock-reset"; ++ reg = <0x01c200cc 0x4>; ++ }; ++ ++ ehci0: ehci0@0x01c14000 { ++ compatible = "allwinner,sunxi-ehci"; ++ reg = <0x01c14000 0x400 0x01c14800 0x4 0x01c13404 0x4>; ++ interrupts = <0 39 1>; ++ resets = <&usb_rst 1>; ++ reset-names = "ehci_reset"; ++ clocks = <&usb 8>, <&ahb_gates 1>; ++ clock-names = "usb_phy", "ahb_ehci"; ++ status = "disabled"; ++ }; ++ ++ ehci1: ehci1@0x01c1c000 { ++ compatible = "allwinner,sunxi-ehci"; ++ reg = <0x01c1c000 0x400 0x01c1c800 0x4 0x01c13404 0x4>; ++ interrupts = <0 40 1>; ++ resets = <&usb_rst 2>; ++ reset-names = "ehci_reset"; ++ clocks = <&usb 8>, <&ahb_gates 3>; ++ clock-names = "usb_phy", "ahb_ehci"; ++ status = "disabled"; ++ }; + }; + }; +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/158-sun5i-add-dt-bindings-for-usbclocks.patch b/target/linux/sunxi/patches-3.12/158-sun5i-add-dt-bindings-for-usbclocks.patch new file mode 100644 index 0000000000..a8dd56e46d --- /dev/null +++ b/target/linux/sunxi/patches-3.12/158-sun5i-add-dt-bindings-for-usbclocks.patch @@ -0,0 +1,31 @@ +From f4eb27ab7c9893a65fd414451459899cdd6334a7 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Tue, 24 Sep 2013 20:02:39 +0200 +Subject: [PATCH] ARM: sun5i: dt: Add bindings for USB Host clocks + +--- + arch/arm/boot/dts/sun5i-a13.dtsi | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi +index 9ac706a..aad270c 100644 +--- a/arch/arm/boot/dts/sun5i-a13.dtsi ++++ b/arch/arm/boot/dts/sun5i-a13.dtsi +@@ -90,6 +90,14 @@ + clock-output-names = "pll6_sata", "pll6_other", "pll6"; + }; + ++ usb:usb@0x01c200cc { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun5i-usb-gates-clk"; ++ reg = <0x01c200cc 0x4>; ++ clocks = <&pll6 1>; ++ clock-output-names = "usb_ohci0", "usb_phy"; ++ }; ++ + /* dummy is 200M */ + cpu: cpu@01c20054 { + #clock-cells = <0>; +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/159-sun5i-add-support-for-usbclocks.patch b/target/linux/sunxi/patches-3.12/159-sun5i-add-support-for-usbclocks.patch new file mode 100644 index 0000000000..c9445a2d34 --- /dev/null +++ b/target/linux/sunxi/patches-3.12/159-sun5i-add-support-for-usbclocks.patch @@ -0,0 +1,35 @@ +From aaf8700dfa1b19bbb994e2996bd293190c0cefbd Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Sun, 6 Oct 2013 14:04:50 +0200 +Subject: [PATCH] clk: sun5i: Add support for USB clocks + +--- + drivers/clk/sunxi/clk-sunxi.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c +index cbe1516..f9b8b18 100644 +--- a/drivers/clk/sunxi/clk-sunxi.c ++++ b/drivers/clk/sunxi/clk-sunxi.c +@@ -623,6 +623,10 @@ struct gates_data { + .mask = {0x1C0}, + }; + ++static const struct gates_data sun5i_usb_gates_data __initconst = { ++ .mask = {0x140}, ++}; ++ + static const struct gates_data sun5i_a10s_ahb_gates_data __initconst = { + .mask = {0x147667e7, 0x185915}, + }; +@@ -874,6 +878,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node, + {.compatible = "allwinner,sun47i-usb-gates-clk", .data = &sun47i_usb_gates_data,}, + {.compatible = "allwinner,sun5i-a10s-ahb-gates-clk", .data = &sun5i_a10s_ahb_gates_data,}, + {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,}, ++ {.compatible = "allwinner,sun5i-usb-gates-clk", .data = &sun5i_usb_gates_data,}, + {.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,}, + {.compatible = "allwinner,sun7i-a20-ahb-gates-clk", .data = &sun7i_a20_ahb_gates_data,}, + {.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &sun4i_apb0_gates_data,}, +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/160-sun5i-dt-add-usb-ehci-bindings.patch b/target/linux/sunxi/patches-3.12/160-sun5i-dt-add-usb-ehci-bindings.patch new file mode 100644 index 0000000000..70e54d5247 --- /dev/null +++ b/target/linux/sunxi/patches-3.12/160-sun5i-dt-add-usb-ehci-bindings.patch @@ -0,0 +1,50 @@ +From d3f751a7afe959d53c2b9e71a25921aeb38e0837 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Tue, 24 Sep 2013 20:03:40 +0200 +Subject: [PATCH] ARM: sun5i: dt: Add USB EHCI bindings + +--- + arch/arm/boot/dts/sun5i-a13.dtsi | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi +index aad270c..a271a2d 100644 +--- a/arch/arm/boot/dts/sun5i-a13.dtsi ++++ b/arch/arm/boot/dts/sun5i-a13.dtsi +@@ -16,6 +16,10 @@ + / { + interrupt-parent = <&intc>; + ++ aliases { ++ ehci1 = &ehci0; ++ }; ++ + cpus { + #address-cells = <1>; + #size-cells = <0>; +@@ -310,5 +314,22 @@ + interrupts = <82>, <83>; + clocks = <&ahb_gates 28>; + }; ++ ++ usb_rst: reset@0x01c200cc { ++ #reset-cells = <1>; ++ compatible = "allwinner,sun4i-clock-reset"; ++ reg = <0x01c200cc 0x4>; ++ }; ++ ++ ehci0: ehci0@0x01c14000 { ++ compatible = "allwinner,sunxi-ehci"; ++ reg = <0x01c14000 0x400 0x01c14800 0x4 0x01c13404 0x4>; ++ interrupts = <39>; ++ resets = <&usb_rst 1>; ++ reset-names = "ehci_reset"; ++ clocks = <&usb 8>, <&ahb_gates 1>; ++ clock-names = "usb_phy", "ahb_ehci"; ++ status = "disabled"; ++ }; + }; + }; +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/161-sun5i-add-dt-ehci-for-a13-olinuxino.patch b/target/linux/sunxi/patches-3.12/161-sun5i-add-dt-ehci-for-a13-olinuxino.patch new file mode 100644 index 0000000000..362d85b1c5 --- /dev/null +++ b/target/linux/sunxi/patches-3.12/161-sun5i-add-dt-ehci-for-a13-olinuxino.patch @@ -0,0 +1,62 @@ +From 0944583d288e594d10ed0015b3d45839c70f8931 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Tue, 24 Sep 2013 20:07:53 +0200 +Subject: [PATCH] ARM: sun5i: dt: Add EHCI bindings to A13-Olinuxino + +--- + arch/arm/boot/dts/sun5i-a13-olinuxino.dts | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts +index 9e508dc..e30b89f 100644 +--- a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts ++++ b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts +@@ -30,6 +30,13 @@ + allwinner,drive = <1>; + allwinner,pull = <0>; + }; ++ ++ usb1_vbus_pin: usb1_vbus_pin@0 { ++ allwinner,pins = "PG11"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <2>; ++ }; + }; + + uart1: serial@01c28400 { +@@ -55,6 +62,11 @@ + pinctrl-0 = <&i2c2_pins_a>; + status = "okay"; + }; ++ ++ ehci0: ehci0@0x01c14000 { ++ vbus-supply = <®_usb1_vbus>; ++ status = "okay"; ++ }; + }; + + leds { +@@ -67,4 +79,19 @@ + default-state = "on"; + }; + }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ ++ reg_usb1_vbus: usb1-vbus { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb1_vbus_pin>; ++ regulator-name = "usb1-vbus"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ enable-active-high; ++ gpio = <&pio 6 11 0>; ++ }; ++ }; + }; +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/162-add-dt-ehci-for-a20-olinuxino.patch b/target/linux/sunxi/patches-3.12/162-add-dt-ehci-for-a20-olinuxino.patch new file mode 100644 index 0000000000..40706d2e23 --- /dev/null +++ b/target/linux/sunxi/patches-3.12/162-add-dt-ehci-for-a20-olinuxino.patch @@ -0,0 +1,84 @@ +From 630ccdf33652f8e35b8c84e939d5a86fad9612e2 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Thu, 19 Sep 2013 21:50:21 +0200 +Subject: [PATCH] ARM: sun7i: dt: Add USB EHCI bindings for A20-Olinuxino + +--- + arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts | 49 +++++++++++++++++++++++++ + 1 file changed, 49 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts +index ead3013..e6b1e26 100644 +--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts ++++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts +@@ -41,6 +41,20 @@ + allwinner,drive = <1>; + allwinner,pull = <0>; + }; ++ ++ usb1_vbus_pin: usb1_vbus_pin@0 { ++ allwinner,pins = "PH6"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <2>; ++ }; ++ ++ usb2_vbus_pin: usb2_vbus_pin@0 { ++ allwinner,pins = "PH3"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <2>; ++ }; + }; + + uart0: serial@01c28000 { +@@ -76,6 +90,15 @@ + i2c2: i2c@01c2b400 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_pins_a>; ++ }; ++ ++ ehci0: ehci0@0x01c14000 { ++ vbus-supply = <®_usb1_vbus>; ++ status = "okay"; ++ }; ++ ++ ehci1: ehci1@0x01c1c000 { ++ vbus-supply = <®_usb2_vbus>; + status = "okay"; + }; + }; +@@ -91,4 +114,30 @@ + default-state = "on"; + }; + }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ ++ reg_usb1_vbus: usb1-vbus { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb1_vbus_pin>; ++ regulator-name = "usb1-vbus"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ enable-active-high; ++ gpio = <&pio 7 6 0>; ++ }; ++ ++ reg_usb2_vbus: usb2-vbus { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb2_vbus_pin>; ++ regulator-name = "usb2-vbus"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ enable-active-high; ++ gpio = <&pio 7 3 0>; ++ }; ++ }; + }; +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/170-sunxi-sid-initial.patch b/target/linux/sunxi/patches-3.12/170-sunxi-sid-initial.patch new file mode 100644 index 0000000000..8407b2f998 --- /dev/null +++ b/target/linux/sunxi/patches-3.12/170-sunxi-sid-initial.patch @@ -0,0 +1,290 @@ +From 1d4b3ab562fa87e2c7f05cf92af1ff4b6cd42581 Mon Sep 17 00:00:00 2001 +From: Oliver Schinagl <oliver@schinagl.nl> +Date: Tue, 3 Sep 2013 12:33:27 +0200 +Subject: [PATCH] ARM: sunxi: Initial support for Allwinner's Security ID fuses + +Allwinner has electric fuses (efuse) on their line of chips. This driver +reads those fuses, seeds the kernel entropy and exports them as a sysfs +node. + +These fuses are most likely to be programmed at the factory, encoding +things like Chip ID, some sort of serial number, etc. and appear to be +reasonably unique. +While in theory, these should be writeable by the user, it will probably +be inconvenient to do so. Allwinner recommends that a certain input pin, +labeled 'efuse_vddq', be connected to GND. To write these fuses however, +a 2.5 V programming voltage needs to be applied to this pin. + +Even so, they can still be used to generate a board-unique mac from, +board unique RSA key and seed the kernel RNG. + +On sun7i additional storage is available, this is initially used for an +UEFI BOOT key, Secure JTAG key, HDMI-HDCP key and vendor specific keys. + +Currently supported are the following known chips: +Allwinner sun4i (A10) +Allwinner sun5i (A10s, A13) +Allwinner sun7i (A20) + +Signed-off-by: Oliver Schinagl <oliver@schinagl.nl> +--- + Documentation/ABI/testing/sysfs-driver-sunxi-sid | 22 +++ + .../bindings/misc/allwinner,sunxi-sid.txt | 17 +++ + drivers/misc/eeprom/Kconfig | 13 ++ + drivers/misc/eeprom/Makefile | 1 + + drivers/misc/eeprom/sunxi_sid.c | 158 +++++++++++++++++++++ + 5 files changed, 211 insertions(+) + create mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid + create mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt + create mode 100644 drivers/misc/eeprom/sunxi_sid.c + +diff --git a/Documentation/ABI/testing/sysfs-driver-sunxi-sid b/Documentation/ABI/testing/sysfs-driver-sunxi-sid +new file mode 100644 +index 0000000..ffb9536 +--- /dev/null ++++ b/Documentation/ABI/testing/sysfs-driver-sunxi-sid +@@ -0,0 +1,22 @@ ++What: /sys/devices/*/<our-device>/eeprom ++Date: August 2013 ++Contact: Oliver Schinagl <oliver@schinagl.nl> ++Description: read-only access to the SID (Security-ID) on current ++ A-series SoC's from Allwinner. Currently supports A10, A10s, A13 ++ and A20 CPU's. The earlier A1x series of SoCs exports 16 bytes, ++ whereas the newer A20 SoC exposes 512 bytes split into sections. ++ Besides the 16 bytes of SID, there's also an SJTAG area, ++ HDMI-HDCP key and some custom keys. Below a quick overview, for ++ details see the user manual: ++ 0x000 128 bit root-key (sun[457]i) ++ 0x010 128 bit boot-key (sun7i) ++ 0x020 64 bit security-jtag-key (sun7i) ++ 0x028 16 bit key configuration (sun7i) ++ 0x02b 16 bit custom-vendor-key (sun7i) ++ 0x02c 320 bit low general key (sun7i) ++ 0x040 32 bit read-control access (sun7i) ++ 0x064 224 bit low general key (sun7i) ++ 0x080 2304 bit HDCP-key (sun7i) ++ 0x1a0 768 bit high general key (sun7i) ++Users: any user space application which wants to read the SID on ++ Allwinner's A-series of CPU's. +diff --git a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt +new file mode 100644 +index 0000000..68ba372 +--- /dev/null ++++ b/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt +@@ -0,0 +1,17 @@ ++Allwinner sunxi-sid ++ ++Required properties: ++- compatible: "allwinner,sun4i-sid" or "allwinner,sun7i-a20-sid". ++- reg: Should contain registers location and length ++ ++Example for sun4i: ++ sid@01c23800 { ++ compatible = "allwinner,sun4i-sid"; ++ reg = <0x01c23800 0x10> ++ }; ++ ++Example for sun7i: ++ sid@01c23800 { ++ compatible = "allwinner,sun7i-a20-sid"; ++ reg = <0x01c23800 0x200> ++ }; +diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig +index 04f2e1f..9536852f 100644 +--- a/drivers/misc/eeprom/Kconfig ++++ b/drivers/misc/eeprom/Kconfig +@@ -96,4 +96,17 @@ config EEPROM_DIGSY_MTC_CFG + + If unsure, say N. + ++config EEPROM_SUNXI_SID ++ tristate "Allwinner sunxi security ID support" ++ depends on ARCH_SUNXI && SYSFS ++ help ++ This is a driver for the 'security ID' available on various Allwinner ++ devices. ++ ++ Due to the potential risks involved with changing e-fuses, ++ this driver is read-only. ++ ++ This driver can also be built as a module. If so, the module ++ will be called sunxi_sid. ++ + endmenu +diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile +index fc1e81d..9507aec 100644 +--- a/drivers/misc/eeprom/Makefile ++++ b/drivers/misc/eeprom/Makefile +@@ -4,4 +4,5 @@ obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o + obj-$(CONFIG_EEPROM_MAX6875) += max6875.o + obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o + obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o ++obj-$(CONFIG_EEPROM_SUNXI_SID) += sunxi_sid.o + obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o +diff --git a/drivers/misc/eeprom/sunxi_sid.c b/drivers/misc/eeprom/sunxi_sid.c +new file mode 100644 +index 0000000..9c34e57 +--- /dev/null ++++ b/drivers/misc/eeprom/sunxi_sid.c +@@ -0,0 +1,158 @@ ++/* ++ * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl> ++ * http://www.linux-sunxi.org ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * This driver exposes the Allwinner security ID, efuses exported in byte- ++ * sized chunks. ++ */ ++ ++#include <linux/compiler.h> ++#include <linux/device.h> ++#include <linux/err.h> ++#include <linux/export.h> ++#include <linux/fs.h> ++#include <linux/init.h> ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/kobject.h> ++#include <linux/module.h> ++#include <linux/of_device.h> ++#include <linux/platform_device.h> ++#include <linux/random.h> ++#include <linux/slab.h> ++#include <linux/stat.h> ++#include <linux/sysfs.h> ++#include <linux/types.h> ++ ++#define DRV_NAME "sunxi-sid" ++ ++struct sunxi_sid_data { ++ void __iomem *reg_base; ++ unsigned int keysize; ++}; ++ ++/* We read the entire key, due to a 32 bit read alignment requirement. Since we ++ * want to return the requested byte, this results in somewhat slower code and ++ * uses 4 times more reads as needed but keeps code simpler. Since the SID is ++ * only very rarely probed, this is not really an issue. ++ */ ++static u8 sunxi_sid_read_byte(const struct sunxi_sid_data *sid_data, ++ const unsigned int offset) ++{ ++ u32 sid_key; ++ ++ if (offset >= sid_data->keysize) ++ return 0; ++ ++ sid_key = ioread32be(sid_data->reg_base + round_down(offset, 4)); ++ sid_key >>= (offset % 4) * 8; ++ ++ return sid_key; /* Only return the last byte */ ++} ++ ++static ssize_t sid_read(struct file *fd, struct kobject *kobj, ++ struct bin_attribute *attr, char *buf, ++ loff_t pos, size_t size) ++{ ++ struct platform_device *pdev; ++ struct sunxi_sid_data *sid_data; ++ int i; ++ ++ pdev = to_platform_device(kobj_to_dev(kobj)); ++ sid_data = platform_get_drvdata(pdev); ++ ++ if (pos < 0 || pos >= sid_data->keysize) ++ return 0; ++ if (size > sid_data->keysize - pos) ++ size = sid_data->keysize - pos; ++ ++ for (i = 0; i < size; i++) ++ buf[i] = sunxi_sid_read_byte(sid_data, pos + i); ++ ++ return i; ++} ++ ++static struct bin_attribute sid_bin_attr = { ++ .attr = { .name = "eeprom", .mode = S_IRUGO, }, ++ .read = sid_read, ++}; ++ ++static int sunxi_sid_remove(struct platform_device *pdev) ++{ ++ device_remove_bin_file(&pdev->dev, &sid_bin_attr); ++ dev_dbg(&pdev->dev, "driver unloaded\n"); ++ ++ return 0; ++} ++ ++static const struct of_device_id sunxi_sid_of_match[] = { ++ { .compatible = "allwinner,sun4i-sid", .data = (void *)16}, ++ { .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512}, ++ {/* sentinel */}, ++}; ++MODULE_DEVICE_TABLE(of, sunxi_sid_of_match); ++ ++static int sunxi_sid_probe(struct platform_device *pdev) ++{ ++ struct sunxi_sid_data *sid_data; ++ struct resource *res; ++ const struct of_device_id *of_dev_id; ++ u8 *entropy; ++ unsigned int i; ++ ++ sid_data = devm_kzalloc(&pdev->dev, sizeof(struct sunxi_sid_data), ++ GFP_KERNEL); ++ if (!sid_data) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ sid_data->reg_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(sid_data->reg_base)) ++ return PTR_ERR(sid_data->reg_base); ++ ++ of_dev_id = of_match_device(sunxi_sid_of_match, &pdev->dev); ++ if (!of_dev_id) ++ return -ENODEV; ++ sid_data->keysize = (int)of_dev_id->data; ++ ++ platform_set_drvdata(pdev, sid_data); ++ ++ sid_bin_attr.size = sid_data->keysize; ++ if (device_create_bin_file(&pdev->dev, &sid_bin_attr)) ++ return -ENODEV; ++ ++ entropy = kzalloc(sizeof(u8) * sid_data->keysize, GFP_KERNEL); ++ for (i = 0; i < sid_data->keysize; i++) ++ entropy[i] = sunxi_sid_read_byte(sid_data, i); ++ add_device_randomness(entropy, sid_data->keysize); ++ kfree(entropy); ++ ++ dev_dbg(&pdev->dev, "loaded\n"); ++ ++ return 0; ++} ++ ++static struct platform_driver sunxi_sid_driver = { ++ .probe = sunxi_sid_probe, ++ .remove = sunxi_sid_remove, ++ .driver = { ++ .name = DRV_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = sunxi_sid_of_match, ++ }, ++}; ++module_platform_driver(sunxi_sid_driver); ++ ++MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>"); ++MODULE_DESCRIPTION("Allwinner sunxi security id driver"); ++MODULE_LICENSE("GPL"); +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/171-add-dt-sunxi-sid.patch b/target/linux/sunxi/patches-3.12/171-add-dt-sunxi-sid.patch new file mode 100644 index 0000000000..55a654f5e1 --- /dev/null +++ b/target/linux/sunxi/patches-3.12/171-add-dt-sunxi-sid.patch @@ -0,0 +1,84 @@ +From 3c6625e46113e600fb83468c9a963a10c5cebedc Mon Sep 17 00:00:00 2001 +From: Oliver Schinagl <oliver@schinagl.nl> +Date: Tue, 3 Sep 2013 12:33:28 +0200 +Subject: [PATCH] ARM: sunxi: dt: Add sunxi-sid to dts for sun4i, sun5i and + sun7i + +This patch shall add support for the sunxi-sid driver to the device +tree for A10, A10s, A13 and A20. + +Signed-off-by: Oliver Schinagl <oliver@schinagl.nl> +--- + arch/arm/boot/dts/sun4i-a10.dtsi | 5 +++++ + arch/arm/boot/dts/sun5i-a10s.dtsi | 5 +++++ + arch/arm/boot/dts/sun5i-a13.dtsi | 5 +++++ + arch/arm/boot/dts/sun7i-a20.dtsi | 5 +++++ + 4 files changed, 20 insertions(+) + +diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi +index c32770a..319cc6b 100644 +--- a/arch/arm/boot/dts/sun4i-a10.dtsi ++++ b/arch/arm/boot/dts/sun4i-a10.dtsi +@@ -266,6 +266,11 @@ + reg = <0x01c20c90 0x10>; + }; + ++ sid: eeprom@01c23800 { ++ compatible = "allwinner,sun4i-sid"; ++ reg = <0x01c23800 0x10>; ++ }; ++ + uart0: serial@01c28000 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28000 0x400>; +diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi +index 3b4a057..5247674 100644 +--- a/arch/arm/boot/dts/sun5i-a10s.dtsi ++++ b/arch/arm/boot/dts/sun5i-a10s.dtsi +@@ -255,6 +255,11 @@ + reg = <0x01c20c90 0x10>; + }; + ++ sid: eeprom@01c23800 { ++ compatible = "allwinner,sun4i-sid"; ++ reg = <0x01c23800 0x10>; ++ }; ++ + uart0: serial@01c28000 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28000 0x400>; +diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi +index f6091dc..ce8ef2a 100644 +--- a/arch/arm/boot/dts/sun5i-a13.dtsi ++++ b/arch/arm/boot/dts/sun5i-a13.dtsi +@@ -222,6 +222,11 @@ + reg = <0x01c20c90 0x10>; + }; + ++ sid: eeprom@01c23800 { ++ compatible = "allwinner,sun4i-sid"; ++ reg = <0x01c23800 0x10>; ++ }; ++ + uart1: serial@01c28400 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28400 0x400>; +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index b939d30..e46cfed 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -265,6 +265,11 @@ + reg = <0x01c20c90 0x10>; + }; + ++ sid: eeprom@01c23800 { ++ compatible = "allwinner,sun7i-a20-sid"; ++ reg = <0x01c23800 0x200>; ++ }; ++ + uart0: serial@01c28000 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28000 0x400>; +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/175-sunxi-rtc.patch b/target/linux/sunxi/patches-3.12/175-sunxi-rtc.patch new file mode 100644 index 0000000000..615658aeef --- /dev/null +++ b/target/linux/sunxi/patches-3.12/175-sunxi-rtc.patch @@ -0,0 +1,542 @@ +From 9b6e3291426efc69d1e8bf257721997f3eeb3009 Mon Sep 17 00:00:00 2001 +From: Carlo Caione <carlo.caione@gmail.com> +Date: Wed, 16 Oct 2013 20:30:27 +0200 +Subject: [PATCH] ARM: sun4i/sun7i: RTC driver + +This patch introduces the driver for the RTC in the Allwinner A10 and +A20 SoCs. + +Signed-off-by: Carlo Caione <carlo.caione@gmail.com> +--- + drivers/rtc/Kconfig | 7 + + drivers/rtc/Makefile | 1 + + drivers/rtc/rtc-sunxi.c | 487 ++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 495 insertions(+) + create mode 100644 drivers/rtc/rtc-sunxi.c + +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index 9654aa3..ef45e0b 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1076,6 +1076,13 @@ config RTC_DRV_SUN4V + If you say Y here you will get support for the Hypervisor + based RTC on SUN4V systems. + ++config RTC_DRV_SUNXI ++ tristate "Allwinner sun4i/sun7i RTC" ++ depends on ARCH_SUNXI ++ help ++ If you say Y here you will get support for the RTC found on ++ Allwinner A10/A20. ++ + config RTC_DRV_STARFIRE + bool "Starfire RTC" + depends on SPARC64 +diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile +index 2dff3d2..8b52b5a 100644 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -115,6 +115,7 @@ obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o + obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o + obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o + obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o ++obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o + obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o + obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o + obj-$(CONFIG_RTC_DRV_TILE) += rtc-tile.o +diff --git a/drivers/rtc/rtc-sunxi.c b/drivers/rtc/rtc-sunxi.c +new file mode 100644 +index 0000000..ccd48ae +--- /dev/null ++++ b/drivers/rtc/rtc-sunxi.c +@@ -0,0 +1,487 @@ ++/* ++ * An RTC driver for Allwinner A10/A20 ++ * ++ * Copyright (c) 2013, Carlo Caione <carlo.caione@gmail.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/err.h> ++#include <linux/fs.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_address.h> ++#include <linux/of_device.h> ++#include <linux/platform_device.h> ++#include <linux/rtc.h> ++#include <linux/types.h> ++ ++#define SUNXI_LOSC_CTRL 0x0000 ++#define SUNXI_LOSC_CTRL_RTC_HMS_ACC BIT(8) ++#define SUNXI_LOSC_CTRL_RTC_YMD_ACC BIT(7) ++ ++#define SUNXI_RTC_YMD 0x0004 ++ ++#define SUNXI_RTC_HMS 0x0008 ++ ++#define SUNXI_ALRM_DHMS 0x000c ++ ++#define SUNXI_ALRM_EN 0x0014 ++#define SUNXI_ALRM_EN_CNT_EN BIT(8) ++ ++#define SUNXI_ALRM_IRQ_EN 0x0018 ++#define SUNXI_ALRM_IRQ_EN_CNT_IRQ_EN BIT(0) ++ ++#define SUNXI_ALRM_IRQ_STA 0x001c ++#define SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND BIT(0) ++ ++#define SUNXI_LOSC_CTRL_RTC_ACC \ ++ (SUNXI_LOSC_CTRL_RTC_HMS_ACC | SUNXI_LOSC_CTRL_RTC_YMD_ACC) ++ ++#define SUNXI_MASK_DH 0x0000001f ++#define SUNXI_MASK_SM 0x0000003f ++#define SUNXI_MASK_M 0x0000000f ++#define SUNXI_MASK_LY 0x00000001 ++#define SUNXI_MASK_D 0x00000ffe ++#define SUNXI_MASK_M 0x0000000f ++ ++#define SUNXI_GET(x, mask, shift) (((x) & ((mask) << (shift))) \ ++ >> (shift)) ++ ++#define SUNXI_SET(x, mask, shift) (((x) & (mask)) << (shift)) ++ ++/* Get date values */ ++#define SUNXI_DATE_GET_DAY_VALUE(x) SUNXI_GET(x, SUNXI_MASK_DH, 0) ++#define SUNXI_DATE_GET_MON_VALUE(x) SUNXI_GET(x, SUNXI_MASK_M, 8) ++#define SUNXI_DATE_GET_YEAR_VALUE(x, mask) SUNXI_GET(x, mask, 16) ++ ++/* Get time values */ ++#define SUNXI_TIME_GET_SEC_VALUE(x) SUNXI_GET(x, SUNXI_MASK_SM, 0) ++#define SUNXI_TIME_GET_MIN_VALUE(x) SUNXI_GET(x, SUNXI_MASK_SM, 8) ++#define SUNXI_TIME_GET_HOUR_VALUE(x) SUNXI_GET(x, SUNXI_MASK_DH, 16) ++ ++/* Get alarm values */ ++#define SUNXI_ALRM_GET_SEC_VALUE(x) SUNXI_GET(x, SUNXI_MASK_SM, 0) ++#define SUNXI_ALRM_GET_MIN_VALUE(x) SUNXI_GET(x, SUNXI_MASK_SM, 8) ++#define SUNXI_ALRM_GET_HOUR_VALUE(x) SUNXI_GET(x, SUNXI_MASK_DH, 16) ++ ++/* Set date values */ ++#define SUNXI_DATE_SET_DAY_VALUE(x) SUNXI_DATE_GET_DAY_VALUE(x) ++#define SUNXI_DATE_SET_MON_VALUE(x) SUNXI_SET(x, SUNXI_MASK_M, 8) ++#define SUNXI_DATE_SET_YEAR_VALUE(x, mask) SUNXI_SET(x, mask, 16) ++#define SUNXI_LEAP_SET_VALUE(x, shift) SUNXI_SET(x, SUNXI_MASK_LY, shift) ++ ++/* Set time values */ ++#define SUNXI_TIME_SET_SEC_VALUE(x) SUNXI_TIME_GET_SEC_VALUE(x) ++#define SUNXI_TIME_SET_MIN_VALUE(x) SUNXI_SET(x, SUNXI_MASK_SM, 8) ++#define SUNXI_TIME_SET_HOUR_VALUE(x) SUNXI_SET(x, SUNXI_MASK_DH, 16) ++ ++/* set alarm values */ ++#define SUNXI_ALRM_SET_SEC_VALUE(x) SUNXI_ALRM_GET_SEC_VALUE(x) ++#define SUNXI_ALRM_SET_MIN_VALUE(x) SUNXI_SET(x, SUNXI_MASK_SM, 8) ++#define SUNXI_ALRM_SET_HOUR_VALUE(x) SUNXI_SET(x, SUNXI_MASK_DH, 16) ++#define SUNXI_ALRM_SET_DAY_VALUE(x) SUNXI_SET(x, SUNXI_MASK_D, 21) ++ ++/* time unit conversions */ ++#define SEC_IN_MIN 60 ++#define SEC_IN_HOUR (60 * SEC_IN_MIN) ++#define SEC_IN_DAY (24 * SEC_IN_HOUR) ++ ++struct sunxi_rtc_data_year { ++ unsigned int min; /* min year allowed */ ++ unsigned int max; /* max year allowed */ ++ unsigned int off; /* data year offset */ ++ unsigned int mask; ++ unsigned char leap_shift; /* bit shift to get the leap year */ ++}; ++ ++static struct sunxi_rtc_data_year data_year_param[] = { ++ [0] = { ++ .min = 1970, ++ .max = 2100, ++ .off = 0, ++ .mask = 0x000000ff, ++ .leap_shift = 24, ++ }, ++ [1] = { ++ .min = 2010, ++ .max = 2073, ++ .off = 110, ++ .mask = 0x0000003f, ++ .leap_shift = 22, ++ }, ++}; ++ ++struct sunxi_rtc_dev { ++ struct rtc_device *rtc; ++ struct device *dev; ++ struct sunxi_rtc_data_year *data_year; ++ void __iomem *base; ++ int irq; ++}; ++ ++static irqreturn_t sunxi_rtc_alarmirq(int irq, void *id) ++{ ++ struct sunxi_rtc_dev *chip = (struct sunxi_rtc_dev *) id; ++ u32 val; ++ ++ val = readl(chip->base + SUNXI_ALRM_IRQ_STA); ++ ++ if (val & SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND) { ++ val |= SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND; ++ writel(val, chip->base + SUNXI_ALRM_IRQ_STA); ++ ++ rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF); ++ ++ return IRQ_HANDLED; ++ } ++ ++ return IRQ_NONE; ++} ++ ++static void sunxi_rtc_setaie(int to, struct sunxi_rtc_dev *chip) ++{ ++ u32 alarm_val = 0; ++ u32 alarm_irq_val = 0; ++ ++ if (to) { ++ alarm_val = readl(chip->base + SUNXI_ALRM_EN); ++ alarm_val |= SUNXI_ALRM_EN_CNT_EN; ++ ++ alarm_irq_val = readl(chip->base + SUNXI_ALRM_IRQ_EN); ++ alarm_irq_val |= SUNXI_ALRM_IRQ_EN_CNT_IRQ_EN; ++ } else { ++ writel(SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND, ++ chip->base + SUNXI_ALRM_IRQ_STA); ++ } ++ ++ writel(alarm_val, chip->base + SUNXI_ALRM_EN); ++ writel(alarm_irq_val, chip->base + SUNXI_ALRM_IRQ_EN); ++} ++ ++static int sunxi_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) ++{ ++ struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); ++ struct rtc_time *alrm_tm = &alrm->time; ++ u32 alarm; ++ u32 alarm_en; ++ u32 date; ++ ++ alarm = readl(chip->base + SUNXI_ALRM_DHMS); ++ date = readl(chip->base + SUNXI_RTC_YMD); ++ ++ alrm_tm->tm_sec = SUNXI_ALRM_GET_SEC_VALUE(alarm); ++ alrm_tm->tm_min = SUNXI_ALRM_GET_MIN_VALUE(alarm); ++ alrm_tm->tm_hour = SUNXI_ALRM_GET_HOUR_VALUE(alarm); ++ ++ alrm_tm->tm_mday = SUNXI_DATE_GET_DAY_VALUE(date); ++ alrm_tm->tm_mon = SUNXI_DATE_GET_MON_VALUE(date); ++ alrm_tm->tm_year = SUNXI_DATE_GET_YEAR_VALUE(date, ++ chip->data_year->mask); ++ ++ alrm_tm->tm_year += chip->data_year->off; ++ alrm_tm->tm_mon -= 1; ++ ++ alarm_en = readl(chip->base + SUNXI_ALRM_IRQ_EN); ++ if (alarm_en & SUNXI_ALRM_EN_CNT_EN) ++ alrm->enabled = 1; ++ ++ return 0; ++} ++ ++static int sunxi_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) ++{ ++ struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); ++ u32 date, time; ++ int t; ++ ++ /* read again if the system was mid-updated ++ */ ++ for (t = 0; t < 2; t++) { ++ date = readl(chip->base + SUNXI_RTC_YMD); ++ time = readl(chip->base + SUNXI_RTC_HMS); ++ ++ rtc_tm->tm_sec = SUNXI_TIME_GET_SEC_VALUE(time); ++ rtc_tm->tm_min = SUNXI_TIME_GET_MIN_VALUE(time); ++ rtc_tm->tm_hour = SUNXI_TIME_GET_HOUR_VALUE(time); ++ ++ rtc_tm->tm_mday = SUNXI_DATE_GET_DAY_VALUE(date); ++ rtc_tm->tm_mon = SUNXI_DATE_GET_MON_VALUE(date); ++ rtc_tm->tm_year = SUNXI_DATE_GET_YEAR_VALUE(date, ++ chip->data_year->mask); ++ ++ if (rtc_tm->tm_sec == 0) ++ msleep(500); ++ else ++ break; ++ } ++ ++ rtc_tm->tm_year += chip->data_year->off; ++ rtc_tm->tm_mon -= 1; ++ ++ return rtc_valid_tm(rtc_tm); ++} ++ ++static int sunxi_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) ++{ ++ struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); ++ struct rtc_time *alrm_tm = &alrm->time; ++ struct rtc_time tm_now; ++ u32 alarm = 0; ++ unsigned long time_now = 0; ++ unsigned long time_set = 0; ++ unsigned long time_gap = 0; ++ unsigned long time_gap_day = 0; ++ unsigned long time_gap_hour = 0; ++ unsigned long time_gap_min = 0; ++ int ret = 0; ++ ++ ret = sunxi_rtc_gettime(dev, &tm_now); ++ if (ret < 0) { ++ dev_err(dev, "Error in getting time\n"); ++ return -EINVAL; ++ } ++ ++ rtc_tm_to_time(alrm_tm, &time_set); ++ rtc_tm_to_time(&tm_now, &time_now); ++ if (time_set <= time_now) { ++ dev_err(dev, "Date to set in the past\n"); ++ return -EINVAL; ++ } ++ ++ time_gap = time_set - time_now; ++ time_gap_day = time_gap / SEC_IN_DAY; ++ time_gap -= time_gap_day * SEC_IN_DAY; ++ time_gap_hour = time_gap / SEC_IN_HOUR; ++ time_gap -= time_gap_hour * SEC_IN_HOUR; ++ time_gap_min = time_gap / SEC_IN_MIN; ++ time_gap -= time_gap_min * SEC_IN_MIN; ++ ++ if (time_gap_day > 255) { ++ dev_err(dev, "Day must be in the range 0 - 255\n"); ++ return -EINVAL; ++ } ++ ++ sunxi_rtc_setaie(0, chip); ++ writel(0, chip->base + SUNXI_ALRM_DHMS); ++ usleep_range(100, 300); ++ ++ alarm = SUNXI_ALRM_SET_SEC_VALUE(time_gap) | ++ SUNXI_ALRM_SET_MIN_VALUE(time_gap_min) | ++ SUNXI_ALRM_SET_HOUR_VALUE(time_gap_hour) | ++ SUNXI_ALRM_SET_DAY_VALUE(time_gap_day); ++ writel(alarm, chip->base + SUNXI_ALRM_DHMS); ++ ++ writel(0, chip->base + SUNXI_ALRM_IRQ_EN); ++ writel(SUNXI_ALRM_IRQ_EN_CNT_IRQ_EN, chip->base + SUNXI_ALRM_IRQ_EN); ++ ++ sunxi_rtc_setaie(alrm->enabled, chip); ++ ++ return 0; ++} ++ ++static int sunxi_rtc_settime(struct device *dev, struct rtc_time *rtc_tm) ++{ ++ struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); ++ u32 date = 0; ++ u32 time = 0; ++ int year; ++ int t; ++ ++ year = rtc_tm->tm_year + 1900; ++ if (year < chip->data_year->min || year > chip->data_year->max) { ++ dev_err(dev, "rtc only supports year in range %d - %d\n", ++ chip->data_year->min, chip->data_year->max); ++ return -EINVAL; ++ } ++ ++ rtc_tm->tm_year -= chip->data_year->off; ++ rtc_tm->tm_mon += 1; ++ ++ date = SUNXI_DATE_SET_DAY_VALUE(rtc_tm->tm_mday) | ++ SUNXI_DATE_SET_MON_VALUE(rtc_tm->tm_mon) | ++ SUNXI_DATE_SET_YEAR_VALUE(rtc_tm->tm_year, ++ chip->data_year->mask); ++ ++ if (is_leap_year(year)) ++ date |= SUNXI_LEAP_SET_VALUE(1, chip->data_year->leap_shift); ++ ++ time = SUNXI_TIME_SET_SEC_VALUE(rtc_tm->tm_sec) | ++ SUNXI_TIME_SET_MIN_VALUE(rtc_tm->tm_min) | ++ SUNXI_TIME_SET_HOUR_VALUE(rtc_tm->tm_hour); ++ ++ writel(0, chip->base + SUNXI_RTC_HMS); ++ writel(0, chip->base + SUNXI_RTC_YMD); ++ ++ writel(time, chip->base + SUNXI_RTC_HMS); ++ ++ /* After writing the RCT HH-MM-SS register, the ++ * SUNXI_LOSC_CTRL_RTC_HMS_ACC bit is set and it will be cleared until ++ * the real writing operation is finished ++ */ ++ for (t = 0; t < 3; t++) { ++ if ((readl(chip->base + SUNXI_LOSC_CTRL) & ++ SUNXI_LOSC_CTRL_RTC_HMS_ACC) && --t) ++ break; ++ else ++ msleep(50); ++ } ++ if (t == 0) { ++ dev_err(dev, "Failed to set rtc time.\n"); ++ return -1; ++ } ++ ++ writel(date, chip->base + SUNXI_RTC_YMD); ++ ++ /* After writing the RCT YY-MM-DD register, the ++ * SUNXI_LOSC_CTRL_RTC_YMD_ACC bit is set and it will be cleared until ++ * the real writing operation is finished ++ */ ++ for (t = 0; t < 3; t++) { ++ if ((readl(chip->base + SUNXI_LOSC_CTRL) & ++ SUNXI_LOSC_CTRL_RTC_YMD_ACC) && --t) ++ break; ++ else ++ msleep(50); ++ } ++ if (t == 0) { ++ dev_err(dev, "Failed to set rtc date.\n"); ++ return -1; ++ } ++ ++ /* wait about 70us to make sure the the time is really written into ++ * target */ ++ usleep_range(70, 100); ++ ++ return 0; ++} ++ ++static int sunxi_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) ++{ ++ struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); ++ ++ if (!enabled) ++ sunxi_rtc_setaie(enabled, chip); ++ ++ return 0; ++} ++ ++static const struct rtc_class_ops sunxi_rtc_ops = { ++ .read_time = sunxi_rtc_gettime, ++ .set_time = sunxi_rtc_settime, ++ .read_alarm = sunxi_rtc_getalarm, ++ .set_alarm = sunxi_rtc_setalarm, ++ .alarm_irq_enable = sunxi_rtc_alarm_irq_enable ++}; ++ ++static const struct of_device_id sunxi_rtc_dt_ids[] = { ++ { .compatible = "allwinner,sun4i-rtc", .data = &data_year_param[0] }, ++ { .compatible = "allwinner,sun7i-a20-rtc", .data = &data_year_param[1] }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, sunxi_rtc_dt_ids); ++ ++ ++static int sunxi_rtc_probe(struct platform_device *pdev) ++{ ++ struct sunxi_rtc_dev *chip; ++ struct resource *res; ++ const struct of_device_id *of_id; ++ int ret; ++ ++ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); ++ if (!chip) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, chip); ++ chip->dev = &pdev->dev; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ chip->base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(chip->base)) ++ return PTR_ERR(chip->base); ++ ++ chip->irq = platform_get_irq(pdev, 0); ++ if (chip->irq < 0) { ++ dev_err(&pdev->dev, "No IRQ resource\n"); ++ return chip->irq; ++ } ++ ret = devm_request_irq(&pdev->dev, chip->irq, sunxi_rtc_alarmirq, ++ 0, dev_name(&pdev->dev), chip); ++ if (ret) { ++ dev_err(&pdev->dev, "Could not request IRQ\n"); ++ return ret; ++ } ++ ++ of_id = of_match_device(sunxi_rtc_dt_ids, &pdev->dev); ++ if (!of_id) { ++ dev_err(&pdev->dev, "Unable to setup RTC data\n"); ++ return -ENODEV; ++ } ++ chip->data_year = (struct sunxi_rtc_data_year *) of_id->data; ++ ++ /* clear the alarm count value */ ++ writel(0, chip->base + SUNXI_ALRM_DHMS); ++ ++ /* disable alarm, not generate irq pending */ ++ writel(0, chip->base + SUNXI_ALRM_EN); ++ ++ /* disable alarm week/cnt irq, unset to cpu */ ++ writel(0, chip->base + SUNXI_ALRM_IRQ_EN); ++ ++ /* clear alarm week/cnt irq pending */ ++ writel(SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND, chip->base + SUNXI_ALRM_IRQ_STA); ++ ++ chip->rtc = rtc_device_register("rtc-sunxi", &pdev->dev, ++ &sunxi_rtc_ops, THIS_MODULE); ++ if (IS_ERR(chip->rtc)) { ++ dev_err(&pdev->dev, "unable to register device\n"); ++ return PTR_ERR(chip->rtc); ++ } ++ ++ dev_info(&pdev->dev, "RTC enabled\n"); ++ ++ return 0; ++} ++ ++static int sunxi_rtc_remove(struct platform_device *pdev) ++{ ++ struct sunxi_rtc_dev *chip = platform_get_drvdata(pdev); ++ ++ rtc_device_unregister(chip->rtc); ++ ++ return 0; ++} ++ ++static struct platform_driver sunxi_rtc_driver = { ++ .probe = sunxi_rtc_probe, ++ .remove = sunxi_rtc_remove, ++ .driver = { ++ .name = "sunxi-rtc", ++ .owner = THIS_MODULE, ++ .of_match_table = sunxi_rtc_dt_ids, ++ }, ++}; ++ ++module_platform_driver(sunxi_rtc_driver); ++ ++MODULE_DESCRIPTION("sunxi RTC driver"); ++MODULE_AUTHOR("Carlo Caione <carlo.caione@gmail.com>"); ++MODULE_LICENSE("GPL"); +-- +1.8.4 + diff --git a/target/linux/sunxi/patches-3.12/176-add-dt-rtc-for-sun4i-7i.patch b/target/linux/sunxi/patches-3.12/176-add-dt-rtc-for-sun4i-7i.patch new file mode 100644 index 0000000000..3c23c742eb --- /dev/null +++ b/target/linux/sunxi/patches-3.12/176-add-dt-rtc-for-sun4i-7i.patch @@ -0,0 +1,50 @@ +From 40a111b1ce47fabcff14a3bff131a4d118ada257 Mon Sep 17 00:00:00 2001 +From: Carlo Caione <carlo.caione@gmail.com> +Date: Wed, 16 Oct 2013 20:30:26 +0200 +Subject: [PATCH] ARM: dts: sun4i/sun7i: add RTC node + +Add the RTC node to DTS for Allwinner A10 and Allwinner A20. + +Signed-off-by: Carlo Caione <carlo.caione@gmail.com> +--- + arch/arm/boot/dts/sun4i-a10.dtsi | 6 ++++++ + arch/arm/boot/dts/sun7i-a20.dtsi | 6 ++++++ + 2 files changed, 12 insertions(+) + +diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi +index 084fef9..04819a7 100644 +--- a/arch/arm/boot/dts/sun4i-a10.dtsi ++++ b/arch/arm/boot/dts/sun4i-a10.dtsi +@@ -393,6 +393,12 @@ + reg = <0x01c20c90 0x10>; + }; + ++ rtc: rtc@01c20d00 { ++ compatible = "allwinner,sun4i-rtc"; ++ reg = <0x01c20d00 0x20>; ++ interrupts = <24>; ++ }; ++ + sid: eeprom@01c23800 { + compatible = "allwinner,sun4i-sid"; + reg = <0x01c23800 0x10>; +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index fe6cf18..b92e17b 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -381,6 +381,12 @@ + reg = <0x01c20c90 0x10>; + }; + ++ rtc: rtc@01c20d00 { ++ compatible = "allwinner,sun7i-a20-rtc"; ++ reg = <0x01c20d00 0x20>; ++ interrupts = <0 24 1>; ++ }; ++ + sid: eeprom@01c23800 { + compatible = "allwinner,sun7i-a20-sid"; + reg = <0x01c23800 0x200>; +-- +1.8.4 + diff --git a/target/linux/sunxi/profiles/01-default.mk b/target/linux/sunxi/profiles/01-default.mk new file mode 100644 index 0000000000..7d83440220 --- /dev/null +++ b/target/linux/sunxi/profiles/01-default.mk @@ -0,0 +1,17 @@ +# +# Copyright (C) 2013 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +define Profile/Default + NAME:=Default package set + PACKAGES += uboot-sunxi-A13-OLinuXino +endef + +define Profile/Default/Description + Default package set compatible with most boards. +endef +$(eval $(call Profile,Default)) + diff --git a/target/linux/sunxi/profiles/a13-olinuxino.mk b/target/linux/sunxi/profiles/a13-olinuxino.mk new file mode 100644 index 0000000000..821bc563ea --- /dev/null +++ b/target/linux/sunxi/profiles/a13-olinuxino.mk @@ -0,0 +1,18 @@ +# +# Copyright (C) 2013 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +define Profile/A13_OLinuXino + NAME:=A13 OLinuXino + PACKAGES:=\ + uboot-sunxi-A13-OLinuXino +endef + +define Profile/A13_OLinuXino/Description + Package set optimized for the Olimex A13 OLinuXino +endef + +$(eval $(call Profile,A13_OLinuXino)) diff --git a/target/linux/sunxi/profiles/a20-olinuxino.mk b/target/linux/sunxi/profiles/a20-olinuxino.mk new file mode 100644 index 0000000000..583885adc7 --- /dev/null +++ b/target/linux/sunxi/profiles/a20-olinuxino.mk @@ -0,0 +1,18 @@ +# +# Copyright (C) 2013 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +define Profile/A20-OLinuXino_MICRO + NAME:=A20 OLinuXino Micro + PACKAGES:=\ + uboot-sunxi-A20-OLinuXino_MICRO +endef + +define Profile/A20-OLinuXino_MICRO/Description + Package set optimized for the Olimex A20 OLinuXino micro +endef + +$(eval $(call Profile,A20-OLinuXino_MICRO)) diff --git a/target/linux/sunxi/profiles/cubieboard.mk b/target/linux/sunxi/profiles/cubieboard.mk new file mode 100644 index 0000000000..2015453b3f --- /dev/null +++ b/target/linux/sunxi/profiles/cubieboard.mk @@ -0,0 +1,18 @@ +# +# Copyright (C) 2013 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +define Profile/Cubieboard + NAME:=Cubieboard + PACKAGES:=\ + uboot-sunxi-Cubieboard +endef + +define Profile/Cubieboard/Description + Package set optimized for the Cubieboard +endef + +$(eval $(call Profile,Cubieboard)) diff --git a/target/linux/sunxi/profiles/cubieboard2.mk b/target/linux/sunxi/profiles/cubieboard2.mk new file mode 100644 index 0000000000..66c0f43da6 --- /dev/null +++ b/target/linux/sunxi/profiles/cubieboard2.mk @@ -0,0 +1,18 @@ +# +# Copyright (C) 2013 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +define Profile/Cubieboard2 + NAME:=Cubieboard2 + PACKAGES:=\ + uboot-sunxi-Cubieboard2 +endef + +define Profile/Cubieboard2/Description + Package set optimized for the Cubieboard2 +endef + +$(eval $(call Profile,Cubieboard2)) |