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
master
Zoltan HERPAI 2013-11-14 23:12:52 +00:00
parent 4e381a077c
commit 448a6b8d51
48 changed files with 4313 additions and 175 deletions

View File

@ -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
# A10: Cortex-A8
# A13: Cortex-A8
# A20: dual Cortex-A7
# A31: quad Cortex-A7
include $(INCLUDE_DIR)/target.mk
KERNELNAME:="zImage dtbs"
$(eval $(call BuildTarget))

View File

@ -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

View File

@ -0,0 +1,9 @@
#!/bin/sh
do_sunxi() {
. /lib/sunxi.sh
sunxi_board_detect
}
boot_hook_add preinit_main do_sunxi

View File

@ -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"
}

View File

@ -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

View File

@ -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))

View File

@ -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

View File

@ -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))

View File

@ -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))

View File

@ -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

View File

@ -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
BOARDS:= \
sun4i-a10-cubieboard \
sun5i-a13-olinuxino \
sun7i-a20-olinuxino-micro \
sun7i-a20-cubieboard2
define Image/BuildKernel/Template
$(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
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 \
$(foreach board,$(BOARDS),
$(CP) $(LINUX_DIR)/arch/arm/boot/dts/$(board).dtb $(BIN_DIR)/
)
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 \
)
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))

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 = <&reg_usb1_vbus>;
+ status = "okay";
+ };
+
+ ehci1: ehci1@0x01c1c000 {
+ vbus-supply = <&reg_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

View File

@ -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 = <&reg_usb1_vbus>;
+ status = "okay";
+ };
+
+ ehci1: ehci1@0x01c1c000 {
+ vbus-supply = <&reg_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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 = <&reg_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

View File

@ -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 = <&reg_usb1_vbus>;
+ status = "okay";
+ };
+
+ ehci1: ehci1@0x01c1c000 {
+ vbus-supply = <&reg_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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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))

View File

@ -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))

View File

@ -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))

View File

@ -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))

View File

@ -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))