diff -uarN a/.scmversion b/.scmversion --- a/.scmversion 1970-01-01 03:00:00.000000000 +0300 +++ b/.scmversion 2019-06-04 09:09:57.000000000 +0300 @@ -0,0 +1 @@ ++ diff -uarN a/Makefile b/Makefile --- a/Makefile 2016-08-28 13:19:20.000000000 +0300 +++ b/Makefile 2018-11-21 06:44:38.000000000 +0300 @@ -1,3 +1,5 @@ +ARCH=arm +CROSS_COMPILE=arm-xm-linux- VERSION = 3 PATCHLEVEL = 10 SUBLEVEL = 103 diff -uarN a/arch/arm/Kconfig b/arch/arm/Kconfig --- a/arch/arm/Kconfig 2016-08-28 13:19:20.000000000 +0300 +++ b/arch/arm/Kconfig 2018-12-06 05:52:16.000000000 +0300 @@ -865,6 +865,29 @@ help Support for older TI OMAP1 (omap7xx, omap15xx or omap16xx) +config ARCH_XM530 + bool "XM 530" + select ARM_AMBA + select HAVE_CLK + select CLKDEV_LOOKUP + select HAVE_SCHED_CLOCK + select GENERIC_TIME + select GENERIC_CLOCKEVENTS + select ARCH_HAS_CPUFREQ + select MIGHT_HAVE_PCI + select HAVE_SMP + select HAVE_ARM_SCU + select MIGHT_HAVE_CACHE_L2X0 + select NEED_MACH_IO_H + select NEED_MACH_MEMORY_H + select ARCH_HAS_CPUFREQ + select HAVE_ARM_TWD if LOCAL_TIMERS + select USB_ARCH_HAS_OHCI + select USB_ARCH_HAS_EHCI + select USB_ARCH_HAS_XHCI + help + This enables support for XM xm530 platform. + endchoice menu "Multiple platform selection" @@ -1029,6 +1052,8 @@ source "arch/arm/mach-zynq/Kconfig" +source "arch/arm/mach-xm530/Kconfig" + # Definitions to make life easier config ARCH_ACORN bool diff -uarN a/arch/arm/Makefile b/arch/arm/Makefile --- a/arch/arm/Makefile 2016-08-28 13:19:20.000000000 +0300 +++ b/arch/arm/Makefile 2018-12-06 05:52:16.000000000 +0300 @@ -202,6 +202,7 @@ machine-$(CONFIG_ARCH_VIRT) += virt machine-$(CONFIG_ARCH_ZYNQ) += zynq machine-$(CONFIG_ARCH_SUNXI) += sunxi +machine-$(CONFIG_ARCH_XM530) += xm530 # Platform directory name. This list is sorted alphanumerically # by CONFIG_* macro name. diff -uarN a/arch/arm/configs/xm530_smp_defconfig b/arch/arm/configs/xm530_smp_defconfig --- a/arch/arm/configs/xm530_smp_defconfig 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/configs/xm530_smp_defconfig 2019-02-14 05:41:45.000000000 +0300 @@ -0,0 +1,1637 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.10.103 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_ARM_PATCH_PHYS_VIRT=y +CONFIG_NEED_MACH_IO_H=y +CONFIG_NEED_MACH_MEMORY_H=y +CONFIG_GENERIC_BUG=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_EXTABLE_SORT=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZMA is not set +CONFIG_KERNEL_XZ=y +# CONFIG_KERNEL_LZO is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_FHANDLE is not set +# CONFIG_AUDIT is not set +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +CONFIG_KTIME_SCALAR=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_IRQ_TIME_ACCOUNTING is not set +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +# CONFIG_TASK_DELAY_ACCT is not set +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_PREEMPT_RCU is not set +CONFIG_RCU_STALL_COMMON=y +# CONFIG_RCU_USER_QS is not set +CONFIG_RCU_FANOUT=32 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_NOCB_CPU is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CGROUPS is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_NAMESPACES is not set +CONFIG_UIDGID_CONVERTED=y +# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_HAVE_UID16=y +CONFIG_HOTPLUG=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +# CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +# CONFIG_ELF_CORE is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +# CONFIG_AIO is not set +# CONFIG_EMBEDDED is not set +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +# CONFIG_PERF_EVENTS is not set +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +# CONFIG_JUMP_LABEL is not set +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_OLD_SIGACTION=y + +# +# GCOV-based kernel profiling +# +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_MODULE_SIG is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +# CONFIG_LBDAF is not set +CONFIG_BLK_DEV_BSG=y +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_DEADLINE=y +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="deadline" +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_MULTIPLATFORM is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP1 is not set +CONFIG_ARCH_XM530=y +# CONFIG_ARCH_XM580 is not set +# CONFIG_PLAT_SPEAR is not set + +# +# xm530 board feature +# +CONFIG_MACH_XM530=y +CONFIG_DEFAULT_BUSCLK=50000000 +CONFIG_ARM_TIMER_SP804=y + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_ARM_VIRT_EXT=y +# CONFIG_SWP_EMULATE is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_KUSER_HELPERS=y +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_CACHE_L2X0=y +CONFIG_CACHE_PL310=y +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_ARM_NR_BANKS=8 +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_PL310_ERRATA_588369 is not set +# CONFIG_ARM_ERRATA_643719 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_PL310_ERRATA_727915 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_PL310_ERRATA_753970 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_PL310_ERRATA_769419 is not set +# CONFIG_ARM_ERRATA_775420 is not set +# CONFIG_ARM_ERRATA_798181 is not set + +# +# Bus support +# +CONFIG_ARM_AMBA=y +# CONFIG_PCI is not set +# CONFIG_PCI_SYSCALL is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +# CONFIG_ARM_CPU_TOPOLOGY is not set +CONFIG_HAVE_ARM_SCU=y +# CONFIG_HAVE_ARM_ARCH_TIMER is not set +CONFIG_HAVE_ARM_TWD=y +# CONFIG_MCPM is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=2 +CONFIG_HOTPLUG_CPU=y +# CONFIG_ARM_PSCI is not set +CONFIG_LOCAL_TIMERS=y +CONFIG_ARCH_NR_GPIO=0 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_HZ=100 +# CONFIG_SCHED_HRTICK is not set +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +# CONFIG_HIGHMEM is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_COMPACTION is not set +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_CLEANCACHE is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set + +# +# Boot options +# +# CONFIG_USE_OF is not set +CONFIG_ATAGS=y +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="mem=128M console=ttyAMA0,115200 console=ttyMTD,blackbox" +CONFIG_CMDLINE_FROM_BOOTLOADER=y +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +# CONFIG_AUTO_ZRELADDR is not set + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +# CONFIG_CPU_IDLE is not set +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +CONFIG_BINFMT_SCRIPT=y +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_COREDUMP=y + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +# CONFIG_PM_RUNTIME is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +# CONFIG_APM_EMULATION is not set +CONFIG_PM_CLK=y +CONFIG_CPU_PM=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_NET_IP_TUNNEL is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_NET_IPVTI is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_LRO=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETLINK_DIAG is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +CONFIG_BQL=y +# CONFIG_BPF_JIT is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +CONFIG_WIRELESS=y +CONFIG_CFG80211=m +# CONFIG_NL80211_TESTMODE is not set +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_INTERNAL_REGDB is not set +# CONFIG_CFG80211_WEXT is not set +# CONFIG_LIB80211 is not set +# CONFIG_MAC80211 is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +CONFIG_HAVE_BPF_JIT=y + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/mdev" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +CONFIG_FW_LOADER=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_DMA_SHARED_BUFFER=y +# CONFIG_CMA is not set + +# +# Bus devices +# +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_SM_FTL is not set +# CONFIG_MTD_OOPS is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +CONFIG_MTD_BLOCK2MTD=y + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOCG3 is not set +CONFIG_MTD_XMSFC=y +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_UBI is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_BLK_DEV_RBD is not set + +# +# Misc devices +# +# CONFIG_ATMEL_PWM is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_SRAM is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_93CX6 is not set + +# +# Texas Instruments shared transport line discipline +# + +# +# Altera FPGA firmware download module +# + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +CONFIG_MII=y +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_VXLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set + +# +# CAIF transport drivers +# + +# +# Distributed Switch Architecture drivers +# +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +CONFIG_ETHERNET=y +CONFIG_NET_CADENCE=y +# CONFIG_ARM_AT91_ETHER is not set +# CONFIG_MACB is not set +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_VENDOR_CIRRUS=y +# CONFIG_CS89x0 is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +CONFIG_NET_VENDOR_FARADAY=y +# CONFIG_FTMAC100 is not set +# CONFIG_FTGMAC100 is not set +CONFIG_NET_VENDOR_INTEL=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_MARVELL=y +# CONFIG_MVMDIO is not set +CONFIG_NET_VENDOR_MICREL=y +# CONFIG_KS8842 is not set +# CONFIG_KS8851_MLL is not set +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_8390=y +# CONFIG_AX88796 is not set +# CONFIG_ETHOC is not set +CONFIG_NET_VENDOR_SEEQ=y +CONFIG_NET_VENDOR_SMSC=y +# CONFIG_SMC91X is not set +# CONFIG_SMC911X is not set +# CONFIG_SMSC911X is not set +CONFIG_NET_VENDOR_STMICRO=y +# CONFIG_STMMAC_ETH is not set +CONFIG_NET_VENDOR_WIZNET=y +# CONFIG_WIZNET_W5100 is not set +# CONFIG_WIZNET_W5300 is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AT803X_PHY is not set +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +CONFIG_MDIO_BITBANG=y +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_IPHETH is not set +CONFIG_WLAN=y +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_ATH_CARDS is not set +# CONFIG_BRCMFMAC is not set +# CONFIG_HOSTAP is not set +# CONFIG_LIBERTAS is not set +# CONFIG_WL_TI is not set +# CONFIG_MWIFIEX is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +CONFIG_NETDEV_1000=y +CONFIG_XMMAC_ETH=y +# CONFIG_ISDN is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_AMBAKMI is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +CONFIG_GAMEPORT=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GAMEPORT_L4=m + +# +# Character devices +# +CONFIG_TTY=y +# CONFIG_VT is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_DEVKMEM is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_AMBA_PL010 is not set +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_I2C is not set +# CONFIG_SPI is not set + +# +# Qualcomm MSM SSBI bus support +# +# CONFIG_SSBI is not set +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +# CONFIG_PTP_1588_CLOCK is not set + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +# CONFIG_PTP_1588_CLOCK_PCH is not set +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_GPIO_DEVRES=y +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_POWER_AVS is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_REGULATOR is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_GOLDFISH is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_EXYNOS_VIDEO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_LOGO is not set +# CONFIG_SOUND is not set +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB_ARCH_HAS_XHCI=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEFAULT_PERSIST is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_XHCI_HCD is not set +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_CHIPIDEA is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_PHY is not set +# CONFIG_USB_GADGET is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set +# CONFIG_MMC_CLKGATE is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=8 +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +CONFIG_MMC_ARASAN=y +# CONFIG_MMC_WIFI is not set +CONFIG_MMC_SD=m +# CONFIG_MMC_ARMMMCI is not set +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_EDAC is not set +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +# CONFIG_AMBA_PL08X is not set +# CONFIG_DW_DMAC is not set +# CONFIG_TIMB_DMA is not set +CONFIG_PL330_DMA=y +CONFIG_DMA_ENGINE=y + +# +# DMA Clients +# +# CONFIG_ASYNC_TX_DMA is not set +CONFIG_DMATEST=m +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set +# CONFIG_VIRT_DRIVERS is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +# CONFIG_STAGING is not set +CONFIG_CLKDEV_LOOKUP=y + +# +# Hardware Spinlock drivers +# +CONFIG_CLKSRC_MMIO=y +# CONFIG_MAILBOX is not set +# CONFIG_IOMMU_SUPPORT is not set + +# +# Remoteproc drivers +# +# CONFIG_STE_MODEM_RPROC is not set + +# +# Rpmsg drivers +# +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +# CONFIG_PWM is not set +CONFIG_ARM_GIC=y +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +CONFIG_AUTOFS4_FS=m +CONFIG_FUSE_FS=y +# CONFIG_CUSE is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=y +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_CMODE_NONE is not set +# CONFIG_JFFS2_CMODE_PRIORITY is not set +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_CMODE_FAVOURLZO=y +# CONFIG_LOGFS is not set +CONFIG_CRAMFS=y +CONFIG_SQUASHFS=y +# CONFIG_SQUASHFS_XATTR is not set +# CONFIG_SQUASHFS_ZLIB is not set +# CONFIG_SQUASHFS_LZO is not set +CONFIG_SQUASHFS_XZ=y +# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set +# CONFIG_SQUASHFS_EMBEDDED is not set +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_F2FS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V2=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_ACL_SUPPORT=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=y +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_CIFS_SMB2 is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=y +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_BOOT_PRINTK_DELAY is not set + +# +# RCU Debugging +# +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACING_SUPPORT=y +# CONFIG_FTRACE is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set +# CONFIG_ARM_UNWIND is not set +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_LL is not set +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +CONFIG_UNCOMPRESS_INCLUDE="mach/uncompress.h" +# CONFIG_OC_ETM is not set +# CONFIG_PID_IN_CONTEXTIDR is not set + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_CMAC is not set +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_GHASH is not set +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=y +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA1_ARM is not set +CONFIG_CRYPTO_SHA256=y +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_ARM is not set +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +# CONFIG_ASYMMETRIC_KEY_TYPE is not set +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=m +# CONFIG_CRC_T10DIF is not set +CONFIG_CRC_ITU_T=y +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +# CONFIG_CRC8 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_XZ_DEC=y +CONFIG_XZ_DEC_X86=y +CONFIG_XZ_DEC_POWERPC=y +CONFIG_XZ_DEC_IA64=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_ARMTHUMB=y +CONFIG_XZ_DEC_SPARC=y +CONFIG_XZ_DEC_BCJ=y +# CONFIG_XZ_DEC_TEST is not set +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y +CONFIG_AVERAGE=y +# CONFIG_CORDIC is not set +# CONFIG_DDR is not set +CONFIG_OID_REGISTRY=y +# CONFIG_VIRTUALIZATION is not set diff -uarN a/arch/arm/include/uapi/asm/setup.h b/arch/arm/include/uapi/asm/setup.h --- a/arch/arm/include/uapi/asm/setup.h 2016-08-28 13:19:20.000000000 +0300 +++ b/arch/arm/include/uapi/asm/setup.h 2018-11-21 06:44:38.000000000 +0300 @@ -126,6 +126,16 @@ char cmdline[1]; /* this is the minimum size */ }; +#define ATAG_XMINFO 0x54410010 +struct tag_xminfo +{ + __u8 xmauto; + __u8 xmuart; + __u8 ethaddr[18]; + __u8 p_id[32]; + __u8 hwid[32]; +}; + /* acorn RiscPC specific information */ #define ATAG_ACORN 0x41000101 @@ -155,6 +165,7 @@ struct tag_revision revision; struct tag_videolfb videolfb; struct tag_cmdline cmdline; + struct tag_xminfo xminfo; /* * Acorn specific diff -uarN a/arch/arm/kernel/atags_parse.c b/arch/arm/kernel/atags_parse.c --- a/arch/arm/kernel/atags_parse.c 2016-08-28 13:19:20.000000000 +0300 +++ b/arch/arm/kernel/atags_parse.c 2018-11-21 06:44:38.000000000 +0300 @@ -139,6 +139,24 @@ __tagtable(ATAG_CMDLINE, parse_tag_cmdline); +struct tag_xminfo xminfo; +EXPORT_SYMBOL(xminfo); + +static int __init parse_tag_xminfo(const struct tag *tag) +{ + memset(&xminfo, 0, sizeof(xminfo)); + xminfo.xmauto = tag->u.xminfo.xmauto; + xminfo.xmuart = tag->u.xminfo.xmuart; + strcpy(xminfo.ethaddr, tag->u.xminfo.ethaddr); + strcpy(xminfo.p_id, tag->u.xminfo.p_id); + strcpy(xminfo.hwid, tag->u.xminfo.hwid); + + return 0; +} +__tagtable(ATAG_XMINFO, parse_tag_xminfo); + + + /* * Scan the tag table for this tag, and call its parse function. * The tag table is built by the linker from all the __tagtable diff -uarN a/arch/arm/mach-xm530/Kconfig b/arch/arm/mach-xm530/Kconfig --- a/arch/arm/mach-xm530/Kconfig 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/Kconfig 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,26 @@ +if ARCH_XM530 + +menu "xm530 board feature" + +config MACH_XM530 + bool "Support xm530 platform" + select CPU_V7 + select ARM_GIC + select ARM_TIMER_SP804 + select PL330 + select DMA_SHARED_BUFFER + help + Includes support for the xm530 platform. + + This includes specific configurations for the module and + its peripherals. + +config DEFAULT_BUSCLK + int "DEFAULT_BUSCLK" + default "50000000" + help + Default AHB clock rate + +endmenu + +endif diff -uarN a/arch/arm/mach-xm530/Makefile b/arch/arm/mach-xm530/Makefile --- a/arch/arm/mach-xm530/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/Makefile 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,6 @@ +obj-y := core.o clock.o timer.o +obj-$(CONFIG_SMP) += platsmp.o headsmp.o +obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o +obj-$(CONFIG_CACHE_L2X0) += l2cache.o +obj-$(CONFIG_DMA_ENGINE) += dma.o + diff -uarN a/arch/arm/mach-xm530/Makefile.boot b/arch/arm/mach-xm530/Makefile.boot --- a/arch/arm/mach-xm530/Makefile.boot 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/Makefile.boot 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,3 @@ +zreladdr-y := 0x80008000 +params_phys-y := 0x00000100 +initrd_phys-y := 0x00800000 diff -uarN a/arch/arm/mach-xm530/clock.c b/arch/arm/mach-xm530/clock.c --- a/arch/arm/mach-xm530/clock.c 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/clock.c 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,241 @@ +/* + * xmsilicon clock Management framework Routines + * + * Author: wangjian + * + * Copyright (C) 2012 xmsilicon Instruments, Inc. + * wangjian + * + * Txms program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static DEFINE_MUTEX(clock_list_lock); +static struct list_head xmclocks; +static DEFINE_MUTEX(clocks_mutex); +static DEFINE_SPINLOCK(clocks_lock); + +static inline void clk_lock_init(struct clk *c) +{ + mutex_init(&c->mutex); + spin_lock_init(&c->spinlock); +} + +struct clk *xm_get_clock_by_name(const char *name) +{ + struct clk *c; + struct clk *ret = NULL; + mutex_lock(&clock_list_lock); + list_for_each_entry(c, &xmclocks, node) { + if (strcmp(c->name, name) == 0) { + ret = c; + break; + } + } + mutex_unlock(&clock_list_lock); + return ret; +} +EXPORT_SYMBOL(xm_get_clock_by_name); + +unsigned long clk_get_rate(struct clk *c) +{ + unsigned long flags; + unsigned long rate; + + spin_lock_irqsave(&clocks_lock, flags); + + rate = c->rate; + + spin_unlock_irqrestore(&clocks_lock, flags); + + return rate; +} +EXPORT_SYMBOL(clk_get_rate); + +int clk_enable(struct clk *c) +{ + int ret = 0; + + unsigned long flags; + /* + * if c->refcnt == 0,clk hasn't been enabled , + * shoud enable if ,else just refcnt ++ + */ + if (c->refcnt == 0) { + if (c->parent) { + ret = clk_enable(c->parent); /* enable parent */ + if (ret) { + WARN(1, "enable clock:%s failed", c->name); + goto out; + } + } + + if (c->ops && c->ops->enable) { + ret = c->ops->enable(c); + if (ret) { /* if enable faild ,disable the parent */ + if (c->parent) + clk_disable(c->parent); + WARN(1, "enable clock:%s failed", c->name); + goto out; + } + } + spin_lock_irqsave(&clocks_lock, flags); + c->state = ON; + c->set = true; + spin_unlock_irqrestore(&clocks_lock, flags); + } + spin_lock_irqsave(&clocks_lock, flags); + c->refcnt++; + spin_unlock_irqrestore(&clocks_lock, flags); +out: + return ret; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *c) +{ + unsigned long flags; + + if (c->refcnt == 0) { + WARN(1, "Attempting to disable clock %s with refcnt 0", + c->name); + return; + } + if (c->refcnt == 1) { + if (c->ops && c->ops->disable) + c->ops->disable(c); + + if (c->parent) + clk_disable(c->parent); + spin_lock_irqsave(&clocks_lock, flags); + c->state = OFF; + spin_unlock_irqrestore(&clocks_lock, flags); + } + spin_lock_irqsave(&clocks_lock, flags); + c->refcnt--; + spin_unlock_irqrestore(&clocks_lock, flags); +} +EXPORT_SYMBOL(clk_disable); + +int clk_set_parent(struct clk *c, struct clk *parent) +{ + int ret = 0; + + if (!c->ops || !c->ops->set_parent) { + ret = -ENOSYS; + goto out; + } + + ret = c->ops->set_parent(c, parent); +out: + return ret; +} +EXPORT_SYMBOL(clk_set_parent); + +struct clk *clk_get_parent(struct clk *c) +{ + return c->parent; +} +EXPORT_SYMBOL(clk_get_parent); + +int clk_set_rate(struct clk *c, unsigned long rate) +{ + int ret = 0; + + if (!c) { + pr_debug("%s->%d\n", __func__, __LINE__); + return 0; + } + + if (!c->ops || !c->ops->set_rate) { + ret = -ENOSYS; + goto out; + } + + if (rate > c->max_rate) + rate = c->max_rate; + + ret = c->ops->set_rate(c, rate); + if (ret) + goto out; + +out: + return ret; +} +EXPORT_SYMBOL(clk_set_rate); + +long clk_round_rate(struct clk *c, unsigned long rate) +{ + long ret; + + if (!c->ops || !c->ops->round_rate) { + ret = -ENOSYS; + goto out; + } + + if (rate > c->max_rate) + rate = c->max_rate; + + ret = c->ops->round_rate(c, rate); + +out: + return ret; +} +EXPORT_SYMBOL(clk_round_rate); + +void clk_init(struct clk *c) +{ + INIT_LIST_HEAD(&xmclocks); + clk_lock_init(c); + + if (c->ops && c->ops->init) + c->ops->init(c); + + if (!c->ops || !c->ops->enable) { + + c->refcnt++; + c->set = true; + + if (c->parent) + c->state = c->parent->state; + else + c->state = ON; + } + + mutex_lock(&clock_list_lock); + list_add(&c->node, &xmclocks); + mutex_unlock(&clock_list_lock); +} +EXPORT_SYMBOL(clk_init); + +void clk_exit(struct clk *c) +{ + if (!c) { + c->refcnt--; + c->set = true; + } + + mutex_lock(&clock_list_lock); + list_del(&c->node); + mutex_unlock(&clock_list_lock); + return; +} +EXPORT_SYMBOL(clk_exit); diff -uarN a/arch/arm/mach-xm530/core.c b/arch/arm/mach-xm530/core.c --- a/arch/arm/mach-xm530/core.c 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/core.c 2018-12-05 14:27:07.000000000 +0300 @@ -0,0 +1,219 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "mach/clock.h" +#include "platsmp.h" + +#define GPIO0_MULT_USE_EN (GPIO_BASE) + + + +static struct map_desc xm530_io_desc[] __initdata = { + { + .virtual = XM530_IOCH1_VIRT, + .pfn = __phys_to_pfn(XM530_IOCH1_PHYS), + .length = XM530_IOCH1_SIZE, + .type = MT_DEVICE + }, + { + .virtual = XM530_IOCH2_VIRT, + .pfn = __phys_to_pfn(XM530_IOCH2_PHYS), + .length = XM530_IOCH2_SIZE, + .type = MT_DEVICE + } +}; + + +void __init xm530_map_io(void) +{ + int i; + + iotable_init(xm530_io_desc, ARRAY_SIZE(xm530_io_desc)); + + for (i = 0; i < ARRAY_SIZE(xm530_io_desc); i++) { + edb_putstr(" V: "); edb_puthex(xm530_io_desc[i].virtual); + edb_putstr(" P: "); edb_puthex(xm530_io_desc[i].pfn); + edb_putstr(" S: "); edb_puthex(xm530_io_desc[i].length); + edb_putstr(" T: "); edb_putul(xm530_io_desc[i].type); + edb_putstr("\n"); + } + + edb_trace(); +} + + +void __iomem *xm530_gic_cpu_base_addr; +void __init xm530_gic_init_irq(void) +{ + edb_trace(); + xm530_gic_cpu_base_addr = __io_address(CFG_GIC_CPU_BASE); +#ifdef CONFIG_LOCAL_TIMERS + gic_init(0, IRQ_LOCALTIMER, __io_address(CFG_GIC_DIST_BASE), + __io_address(CFG_GIC_CPU_BASE)); +#else + gic_init(0, XM530_GIC_IRQ_START, __io_address(CFG_GIC_DIST_BASE), + __io_address(CFG_GIC_CPU_BASE)); +#endif +} + + +//static struct amba_pl011_data uart1_plat_data = { + //.dma_filter = pl330_filter, + //.dma_rx_param = (void *) DMACH_UART1_RX, + //.dma_tx_param = (void *) DMACH_UART1_TX, +//}; + +#define XM_AMBADEV_NAME(name) xm_ambadevice_##name + +#define XM_AMBA_DEVICE(name, busid, base, platdata) \ + static struct amba_device XM_AMBADEV_NAME(name) = \ + {\ + .dev = { \ + .coherent_dma_mask = ~0, \ + .init_name = busid, \ + .platform_data = platdata, \ + }, \ + .res = { \ + .start = base##_BASE, \ + .end = base##_BASE + 0x1000 - 1, \ + .flags = IORESOURCE_IO, \ + }, \ + .dma_mask = ~0, \ + .irq = { base##_IRQ, base##_IRQ, } \ + } + +XM_AMBA_DEVICE(uart0, "uart:0", UART0, NULL); +XM_AMBA_DEVICE(uart1, "uart:1", UART1, NULL); +//XM_AMBA_DEVICE(uart1, "uart:1", UART1, &uart1_plat_data); + +static struct amba_device *amba_devs[] __initdata = { + &XM_AMBADEV_NAME(uart0), + &XM_AMBADEV_NAME(uart1), +}; + +/* + * These are fixed clocks. + */ +static struct clk uart_clk = { + .rate = 12000000, +}; +static struct clk sp804_clk = { + .rate = 12000000, +}; +static struct clk dma_clk = { + .rate = 12000000, +}; + +//正式芯片为CPU时钟的1/4 或与CPU时钟相等 +static struct clk twd_clk = { + .rate = 150000000, +}; + +static struct clk_lookup lookups[] = { + { /* UART0 */ + .dev_id = "uart:0", + .clk = &uart_clk, + }, + { /* UART1 */ + .dev_id = "uart:1", + .clk = &uart_clk, + }, + { /* SP804 timers */ + .dev_id = "sp804", + .clk = &sp804_clk, + }, + { + .dev_id = "dma-pl330", + .clk = &dma_clk, + }, + { + .dev_id = "smp_twd", + .clk = &twd_clk, + }, +}; + +static void __init xm530_init_early(void) +{ + unsigned int tmp; + unsigned int pllclk; + edb_trace(); + tmp = readl(__io_address(PLL_PLLA_CTRL)); + pllclk = 12000000 / (tmp & 0x3F) * ((tmp >> 6) & 0xFFF) / (((tmp >> 19) & 0x1) + 1); + + tmp = readl(__io_address(PLL_CPUCLK_CTRL)); + twd_clk.rate = pllclk / ((tmp & 0xFF) + 1) / (((tmp >> 20) & 0x1) == 0 ? 1 : 4); + + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); + +} + +void __init xm530_init(void) +{ + unsigned long i; + + edb_trace(); + + + for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { + amba_device_register(amba_devs[i], &iomem_resource); + } +} +static void __init xm530_reserve(void) +{ +} +void xm530_restart(char mode, const char *cmd) +{ + writel(1, __io_address(SYS_CTRL_BASE + REG_SYS_SOFT_RSTEN)); + writel(0xca110000, __io_address(SYS_CTRL_BASE + REG_SYS_SOFT_RST)); +} + +extern void __init xm530_timer_init(void); + +asmlinkage void asmprint(void) +{ + edb_trace(); +} + +MACHINE_START(XM530, "xm530") + .atag_offset = 0x100, + .map_io = xm530_map_io, + .init_early = xm530_init_early, + .init_irq = xm530_gic_init_irq, + .init_time = xm530_timer_init, + .init_machine = xm530_init, + .smp = smp_ops(xm530_smp_ops), + .reserve = xm530_reserve, + .restart = xm530_restart, +MACHINE_END diff -uarN a/arch/arm/mach-xm530/dma.c b/arch/arm/mach-xm530/dma.c --- a/arch/arm/mach-xm530/dma.c 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/dma.c 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,57 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +static u8 xm530_dma_peri[] = { + DMACH_MAX, + DMACH_MAX, + DMACH_SPI0_TX, + DMACH_SPI0_RX, + DMACH_SPI1_TX, + DMACH_SPI1_RX, + DMACH_SPI2_TX, + DMACH_SPI2_RX, + DMACH_I2S, + DMACH_UART0_TX, + DMACH_UART0_RX, + DMACH_UART1_TX, + DMACH_UART1_RX, + DMACH_UART2_TX, + DMACH_UART2_RX, + DMACH_I2S_TX, + DMACH_I2S_RX, + DMACH_MAX, +}; + +static struct dma_pl330_platdata xm530_dma_platdata = { + .nr_valid_peri = ARRAY_SIZE(xm530_dma_peri), + .peri_id = xm530_dma_peri, +}; + + +static AMBA_AHB_DEVICE(xm530_dma, "dma-pl330", 0x00041330, + DMAC_BASE, {DMAC_IRQ}, NULL); + +static int __init xm530_dmac_init(void) +{ + dma_cap_set(DMA_SLAVE, xm530_dma_platdata.cap_mask); + dma_cap_set(DMA_CYCLIC, xm530_dma_platdata.cap_mask); + xm530_dma_device.dev.platform_data = &xm530_dma_platdata; + amba_device_register(&xm530_dma_device, &iomem_resource); + + return 0; +} +arch_initcall(xm530_dmac_init); diff -uarN a/arch/arm/mach-xm530/headsmp.S b/arch/arm/mach-xm530/headsmp.S --- a/arch/arm/mach-xm530/headsmp.S 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/headsmp.S 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,92 @@ +/* + * + * clone from linux/arch/arm/mach-realview/headsmp.S + * + * Copyright (c) 2003 ARM Limited + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include + + __CPUINIT + +/* + * Realview specific entry point for secondary CPUs. This provides + * a "holding pen" into which all secondary cores are held until we're + * ready for them to initialise. + */ +ENTRY(xm530_secondary_startup) + + /* set the cpu to SVC32 mode */ + mrs r0, cpsr + bic r0, r0, #0x1f /* r0 = ((~0x1F) & r0) */ + orr r0, r0, #0xd3 /* r0 = (0xd3 | r0) */ + msr cpsr, r0 + + bl flash_cache_all + mrc p15, 0, r0, c0, c0, 5 + and r0, r0, #15 + adr r4, 1f + ldmia r4, {r5, r6} + sub r4, r4, r5 + add r6, r6, r4 +pen: ldr r7, [r6] + cmp r7, r0 + bne pen + + /* + * we've been released from the holding pen: secondary_stack + * should now contain the SVC stack for this core + */ + b secondary_startup + +1: .long . + .long pen_release + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ +@ corrupt: r0, r1, r2, r3 +@ +.align 2 +flash_cache_all: + + /* disable MMU stuff and caches */ + mrc p15, 0, r0, c1, c0, 0 + orr r0, r0, #0x00002000 /* clear bits 13 (--V-) */ + bic r0, r0, #0x00000007 /* clear bits 2:0 (-CAM) */ + orr r0, r0, #0x00000002 /* set bit 1 (--A-) Align */ + orr r0, r0, #0x00000800 /* set bit 12 (Z---) BTB */ + mcr p15, 0, r0, c1, c0, 0 + + /* + * Invalidate L1 I/D + */ + mov r0, #0 /* set up for MCR */ + mcr p15, 0, r0, c8, c7, 0 /* invalidate TLBs */ + mcr p15, 0, r0, c7, c5, 0 /* invalidate icache */ + + /* Invalidate L1 D-cache */ + mcr p15, 2, r0, c0, c0, 0 /* select L1 data cache */ + /* Read Current Cache Size Identification Register */ + mrc p15, 1, r3, c0, c0, 0 + ldr r1, =0x1ff + and r3, r1, r3, LSR #13 /* r3 = (number of sets -1) */ + mov r0, #0 +way_loop: + mov r1, #0 /* r1->set counter */ +line_loop: + mov r2, r0, LSL #30 + orr r2, r1, LSL #5 /* r2->set/way cache-op format */ + mcr p15, 0, r2, c7, c6, 2 /* Invalidate line described by r2 */ + add r1, r1, #1 /* Increment set counter */ + cmp r1, r3 /* Check if the last set is reached */ + ble line_loop /* if not, continue the set_loop */ + add r0, r0, #1 /* else, Increment way counter */ + cmp r0, #4 /* Check if the last way is reached */ + blt way_loop /* if not, continue the way_loop */ + + mov pc, lr diff -uarN a/arch/arm/mach-xm530/hotplug.c b/arch/arm/mach-xm530/hotplug.c --- a/arch/arm/mach-xm530/hotplug.c 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/hotplug.c 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,77 @@ +/****************************************************************************** + * COPYRIGHT (C) 2013 Hisilicon + * All rights reserved. + * *** + * Create by Czyong 2013-12-18 + * +******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + + + +/*****************************************************************************/ + +static inline void xm530_scu_power_off(int cpu) +{ + writel(1, __io_address(SYS_CTRL_BASE + REG_SYS_SOFT_RSTEN)); + writel(0XCA11C100, __io_address(SYS_CTRL_BASE + REG_CPU1_SOFT_RST)); + writel(0, __io_address(SYS_CTRL_BASE + REG_SYS_SOFT_RSTEN)); +} + + +/*****************************************************************************/ + +void xm530_cpu_die(unsigned int cpu) +{ + flush_cache_all(); + xm530_scu_power_off(cpu); + BUG(); +} +/*****************************************************************************/ +/* + * copy startup code to sram, and flash cache. + * @start_addr: slave start phy address + * @jump_addr: slave jump phy address + */ +void set_scu_boot_addr(unsigned int start_addr, unsigned int jump_addr) +{ + unsigned int *virtaddr; + unsigned int *p_virtaddr; + + writel(1, __io_address(SYS_CTRL_BASE + REG_SC_REMAP)); + while(readl(__io_address(SYS_CTRL_BASE + REG_SC_REMAP)) == 0); + + + p_virtaddr = virtaddr = ioremap(start_addr, PAGE_SIZE); + + *p_virtaddr++ = 0xe51ff004; /* ldr pc, [pc, #-4] */ + *p_virtaddr++ = jump_addr; /* pc jump phy address */ + + smp_wmb(); + __cpuc_flush_dcache_area((void *)virtaddr, + (size_t)((char *)p_virtaddr - (char *)virtaddr)); + outer_clean_range(__pa(virtaddr), __pa(p_virtaddr)); + + iounmap(virtaddr); +} +/*****************************************************************************/ + +void xm530_scu_power_up(int cpu) +{ + writel(1, __io_address(SYS_CTRL_BASE + REG_SYS_SOFT_RSTEN)); + if(readl(__io_address(SYS_CTRL_BASE + REG_CPU1_SOFT_RST)) == 1) + { + writel(0XCA11C100, __io_address(SYS_CTRL_BASE + REG_CPU1_SOFT_RST)); + udelay(1); + } + writel(1, __io_address(SYS_CTRL_BASE + REG_CPU1_SOFT_RST)); + writel(0, __io_address(SYS_CTRL_BASE + REG_SYS_SOFT_RSTEN)); +} + diff -uarN a/arch/arm/mach-xm530/hotplug.h b/arch/arm/mach-xm530/hotplug.h --- a/arch/arm/mach-xm530/hotplug.h 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/hotplug.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,20 @@ +/****************************************************************************** + * COPYRIGHT (C) 2013 Hisilicon + * All rights reserved. + * *** + * Create by Czyong 2013-12-18 + * +******************************************************************************/ +#ifndef HOTPLUGH +#define HOTPLUGH +/******************************************************************************/ + +void xm530_cpu_die(unsigned int cpu); + +extern void set_scu_boot_addr(unsigned int start_addr, unsigned int jump_addr); + +void xm530_scu_power_up(int cpu); +void s5_scu_power_up(int cpu); + +/******************************************************************************/ +#endif /* HOTPLUGH */ diff -uarN a/arch/arm/mach-xm530/include/mach/clkdev.h b/arch/arm/mach-xm530/include/mach/clkdev.h --- a/arch/arm/mach-xm530/include/mach/clkdev.h 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/include/mach/clkdev.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,8 @@ +#ifndef __ASM_MACH_CLKDEV_H +#define __ASM_MACH_CLKDEV_H + +#define __clk_get(clk) ({ 1; }) +#define __clk_put(clk) do { } while (0) + +#endif + diff -uarN a/arch/arm/mach-xm530/include/mach/clock.h b/arch/arm/mach-xm530/include/mach/clock.h --- a/arch/arm/mach-xm530/include/mach/clock.h 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/include/mach/clock.h 2018-11-22 14:05:13.000000000 +0300 @@ -0,0 +1,96 @@ +#ifndef __XM_CLOCK_H__ +#define __XM_CLOCK_H__ + +#include +#include +#include +#include +#include + +struct clk; + +/** + * struct clksel_rate - register bitfield values corresponding to clk divisors + * @val: register bitfield value (shifted to bit 0) + * @div: clock divisor corresponding to @val + * @flags: (see "struct clksel_rate.flags possibilities" above) + * + * @val should match the value of a read from struct clk.clksel_reg + * AND'ed with struct clk.clksel_mask, shifted right to bit 0. + * + * @div is the divisor that should be applied to the parent clock's rate + * to produce the current clock's rate. + * + * XXX @flags probably should be replaced with an struct omap_chip. + */ +struct clksel_rate { + u32 val; + u8 div; + u8 flags; +}; + +/** + * struct clksel - available parent clocks, and a pointer to their divisors + * @parent: struct clk * to a possible parent clock + * @rates: available divisors for this parent clock + * + * A struct clksel is always associated with one or more struct clks + * and one or more struct clksel_rates. + */ +struct clksel { + struct clk *parent; + const struct clksel_rate *rates; + unsigned int value; +}; + +enum clk_state { + UNINITIALIZED = 0, + ON, + OFF, +}; + +struct clk_ops { + void (*init)(struct clk *); + int (*enable)(struct clk *clk); + void (*disable)(struct clk *clk); + long (*round_rate)(struct clk *clk, long rate); + int (*set_rate)(struct clk *clk, unsigned rate); + unsigned int (*get_rate)(struct clk *clk); + int (*set_parent)(struct clk *clk, struct clk *parent); + int (*is_enabled)(struct clk *clk); + void (*reset)(struct clk *, bool); +}; + +struct clk { + char *name; + struct clk *parent; + unsigned int refcnt; + unsigned long rate; + unsigned int min_rate; + unsigned int max_rate; + struct clk *child; + struct clk *friend; + enum clk_state state; + bool set; + u32 flags; + struct clk_ops *ops; + struct clksel *clksel; + bool is_enabled; + struct mutex mutex; + spinlock_t spinlock; + struct list_head node; +}; + +void mpu_init_clocks(void); +void clk_init(struct clk *c); +void clk_exit(struct clk *c); + +struct clk *hi_get_clock_by_name(const char *name); +unsigned long clk_get_rate(struct clk *c); +int clk_set_rate(struct clk *c, unsigned long rate); +int clk_enable(struct clk *c); +void clk_disable(struct clk *c); + +#define OSC_FREQ 24000000 + +#endif diff -uarN a/arch/arm/mach-xm530/include/mach/debug-macro.S b/arch/arm/mach-xm530/include/mach/debug-macro.S --- a/arch/arm/mach-xm530/include/mach/debug-macro.S 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/include/mach/debug-macro.S 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,8 @@ +#include + + .macro addruart, rp, rv, tmp + ldr \rp, =UART0_BASE @physical base + ldr \rv, =(UART0_BASE + IO_IOCH1_OFFSET) + .endm + +#include diff -uarN a/arch/arm/mach-xm530/include/mach/dma.h b/arch/arm/mach-xm530/include/mach/dma.h --- a/arch/arm/mach-xm530/include/mach/dma.h 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/include/mach/dma.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,25 @@ +#ifndef __DMA_H_ +#define __DMA_H_ + +enum dma_ch { + DMACH_RES0, + DMACH_RES1, + DMACH_SPI0_TX, + DMACH_SPI0_RX, + DMACH_SPI1_TX, + DMACH_SPI1_RX, + DMACH_SPI2_TX, + DMACH_SPI2_RX, + DMACH_I2S, + DMACH_UART0_TX, + DMACH_UART0_RX, + DMACH_UART1_TX, + DMACH_UART1_RX, + DMACH_UART2_TX, + DMACH_UART2_RX, + DMACH_I2S_TX, + DMACH_I2S_RX, + DMACH_MAX, +}; + +#endif diff -uarN a/arch/arm/mach-xm530/include/mach/early-debug.h b/arch/arm/mach-xm530/include/mach/early-debug.h --- a/arch/arm/mach-xm530/include/mach/early-debug.h 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/include/mach/early-debug.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,36 @@ +#ifndef __ASM_ARCH_EARLY_DEBUG_H +#define __ASM_ARCH_EARLY_DEBUG_H + +#ifdef CONFIG_DEBUG_LL + +extern void printascii(const char *); +extern void printhex8(long); +extern void printch(char); + +#define edb_putc(x) printch(x) +#define edb_putstr(x) printascii(x) +#define edb_puthex(x) printhex8(x) +#define edb_putul(x) printhex8(x) +#define edb_trace() do {\ + edb_putstr(__func__);\ + edb_putstr("\t");\ + edb_putstr("\t");\ + edb_putstr("[");\ + edb_putstr(__FILE__);\ + edb_putstr(":");\ + edb_putul(__LINE__);\ + edb_putstr("]\n");\ +} while (0) + + +#else + +#define edb_putc(x) +#define edb_puthex(x) +#define edb_putul(x) +#define edb_putstr(x) +#define edb_trace(level) + +#endif + +#endif /* __ASM_ARCH_EARLY_DEBUG_H */ diff -uarN a/arch/arm/mach-xm530/include/mach/entry-macro.S b/arch/arm/mach-xm530/include/mach/entry-macro.S --- a/arch/arm/mach-xm530/include/mach/entry-macro.S 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/include/mach/entry-macro.S 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,74 @@ +#include +#include + +.macro disable_fiq +.endm + +.macro get_irqnr_preamble, base, tmp +ldr \base, =xm530_gic_cpu_base_addr +ldr \base, [\base] +.endm + +.macro arch_ret_to_user, tmp1, tmp2 +.endm + +/* + * The interrupt numbering scheme is defined in the + * interrupt controller spec. To wit: + * + * Interrupts 0-15 are IPI + * 16-28 are reserved + * 29-31 are local. We allow 30 to be used for the watchdog. + * 32-1020 are global + * 1021-1022 are reserved + * 1023 is "spurious" (no interrupt) + * + * For now, we ignore all local interrupts so only return an interrupt if it's + * between 30 and 1020. The test_for_ipi routine below will pick up on IPIs. + * + * A simple read from the controller will tell us the number of the highest + * priority enabled interrupt. We then just need to check whether it is in the + * valid range for an IRQ (30-1020 inclusive). + */ + +.macro get_irqnr_and_base, irqnr, irqstat, base, tmp + +ldr \irqstat, [\base, #GIC_CPU_INTACK] /* bits 12-10 = src CPU, + * 9-0 = int # + */ + +ldr \tmp, =1021 + +bic \irqnr, \irqstat, #0x1c00 + +cmp \irqnr, #29 +cmpcc \irqnr, \irqnr +cmpne \irqnr, \tmp +cmpcs \irqnr, \irqnr + +.endm + +/* We assume that irqstat (the raw value of the IRQ acknowledge + * register) is preserved from the macro above. + * If there is an IPI, we immediately signal end of interrupt on the + * controller, since this requires the original irqstat value which + * we won't easily be able to recreate later. + */ + +.macro test_for_ipi, irqnr, irqstat, base, tmp +bic \irqnr, \irqstat, #0x1c00 +cmp \irqnr, #16 +strcc \irqstat, [\base, #GIC_CPU_EOI] +cmpcs \irqnr, \irqnr +.endm + +/* As above, this assumes that irqstat and base are preserved.. */ + +.macro test_for_ltirq, irqnr, irqstat, base, tmp +bic \irqnr, \irqstat, #0x1c00 +mov \tmp, #0 +cmp \irqnr, #29 +moveq \tmp, #1 +streq \irqstat, [\base, #GIC_CPU_EOI] +cmp \tmp, #0 +.endm diff -uarN a/arch/arm/mach-xm530/include/mach/hardware.h b/arch/arm/mach-xm530/include/mach/hardware.h --- a/arch/arm/mach-xm530/include/mach/hardware.h 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/include/mach/hardware.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,13 @@ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include +#include + + +#define __io_address(n) (IOMEM(IO_ADDRESS(n))) + +#define gpio_write(x, y) writel((x), __io_address(GPIO_BASE + (y) * 4)) + +#endif + diff -uarN a/arch/arm/mach-xm530/include/mach/io.h b/arch/arm/mach-xm530/include/mach/io.h --- a/arch/arm/mach-xm530/include/mach/io.h 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/include/mach/io.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,30 @@ +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +#define __io(a) __typesafe_io(a) +#define __mem_pci(a) (a) + +#define XM530_IOCH1_PHYS 0x10000000 /* 0x1000_0000 ~ 0x1010_0000 */ +#define XM530_IOCH2_PHYS 0x20000000 /* 0x2000_0000 ~ 0x2010_0000 */ +#define XM530_IOCH1_SIZE 0x100000 /*1M*/ +#define XM530_IOCH2_SIZE 0x300000 + +#define XM530_IOCH1_VIRT 0xFE000000 +#define XM530_IOCH2_VIRT (XM530_IOCH1_VIRT + XM530_IOCH1_SIZE) + +/* + * physical addr <---> virtual addr + * [0x1000_0000 ~ 0x1010_0000) <---> [0xFE00_0000 ~ 0xFE10_0000) + * [0x2000_0000 ~ 0x2030_0000) <---> [0xFE10_0000 ~ 0xFE40_0000) + */ + +#define IO_IOCH1_OFFSET (XM530_IOCH1_VIRT - XM530_IOCH1_PHYS) +#define IO_IOCH2_OFFSET (XM530_IOCH2_VIRT - XM530_IOCH2_PHYS) + +#define IO_ADDRESS(x) ((x) >= XM530_IOCH2_PHYS ? (x) + IO_IOCH2_OFFSET\ + : (x) + IO_IOCH1_OFFSET) + + +#endif diff -uarN a/arch/arm/mach-xm530/include/mach/irqs.h b/arch/arm/mach-xm530/include/mach/irqs.h --- a/arch/arm/mach-xm530/include/mach/irqs.h 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/include/mach/irqs.h 2019-02-14 05:41:45.000000000 +0300 @@ -0,0 +1,22 @@ +#ifndef __XM_IRQS_H__ +#define __XM_IRQS_H__ + +#define IRQ_LOCALTIMER (29) +#define XM530_GIC_IRQ_START (32) + +#define INTNR_TIMER_0 (XM530_GIC_IRQ_START + 4) /* 36 */ +#define INTNR_TIMER_1 (XM530_GIC_IRQ_START + 4) +#define INTNR_TIMER_2 (XM530_GIC_IRQ_START + 5) /* 37 */ +#define INTNR_TIMER_3 (XM530_GIC_IRQ_START + 5) +#define UART0_IRQ (XM530_GIC_IRQ_START + 0) +#define UART1_IRQ (XM530_GIC_IRQ_START + 1) +#define UART2_IRQ (XM530_GIC_IRQ_START + 2) +#define DMAC_IRQ (XM530_GIC_IRQ_START + 10) +#define GMAC_IRQ (XM530_GIC_IRQ_START + 3) + +#define SDIO0_IRQ (XM530_GIC_IRQ_START + 41) +#define SDIO1_IRQ (XM530_GIC_IRQ_START + 42) + +#define NR_IRQS (XM530_GIC_IRQ_START + 64) + +#endif diff -uarN a/arch/arm/mach-xm530/include/mach/memory.h b/arch/arm/mach-xm530/include/mach/memory.h --- a/arch/arm/mach-xm530/include/mach/memory.h 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/include/mach/memory.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,9 @@ +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +/* + * Physical DRAM offset. + */ +#define PLAT_PHYS_OFFSET UL(0x80000000) + +#endif /* __ASM_ARCH_MEMORY_H */ diff -uarN a/arch/arm/mach-xm530/include/mach/platform.h b/arch/arm/mach-xm530/include/mach/platform.h --- a/arch/arm/mach-xm530/include/mach/platform.h 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/include/mach/platform.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,101 @@ +#ifndef __XM_CHIP_REGS_H__ +#define __XM_CHIP_REGS_H__ + +#include + +/*#define DDR_BASE 0x80000000*/ +/**//*#define DDRC_BASE 0x20110000*/ +/**//*#define IOCONFIG_BASE 0x200F0000*/ +#define UART0_BASE 0x10030000 +#define UART1_BASE 0x10040000 +#define UART2_BASE 0x10050000 +#define SYS_CTRL_BASE 0x20000000 +#define ARM_INTNL_BASE 0x20200000 +#define REG_BASE_L2CACHE 0x20210000 + +#define PLL_PLLA_CTRL 0x20000008 +#define PLL_CPUCLK_CTRL 0x20000028 + +/*#define WDG_BASE 0x20040000*/ +/*#define CRG_REG_BASE 0x20030000*/ + +#define TIMER0_REG_BASE 0x100C0000 +#define TIMER1_REG_BASE 0x100C0020 +#define TIMER2_REG_BASE 0x100D0000 +#define TIMER3_REG_BASE 0x100D0020 + +#define GMAC_BASE 0x10010000 +#define GPIO_BASE 0x10020000 +#define INTC_BASE 0x20010000 +#define DMAC_BASE 0x20020000 + +#define SDIO0_BASE 0x50000000 +#define SDIO1_BASE 0x50100000 + + +#define REG_A5_PERI_SCU 0x0000 +#define REG_A5_PERI_PRI_TIMER_WDT 0x0600 +#define A5_GIC_OFFSET 0x100 +#define A5_GIC_DIST 0x1000 +#define CFG_GIC_CPU_BASE (ARM_INTNL_BASE + A5_GIC_OFFSET) +#define CFG_GIC_DIST_BASE (ARM_INTNL_BASE + A5_GIC_DIST) + + + +#define REG_INTC_IRQSTATUS 0x000 +#define REG_INTC_FIQSTATUS 0x004 +#define REG_INTC_RAWSTATUS 0x008 +#define REG_INTC_INTSELECT 0x00C +#define REG_INTC_INTENABLE 0x010 +#define REG_INTC_INTENCLEAR 0x014 +#define REG_INTC_SOFTINT 0x018 +#define REG_INTC_SOFTINTCLEAR 0x01C + +#define INTNR_IRQ_START 0 +#define INTNR_IRQ_END 31 + +#define REG_TIMER_RELOAD 0x000 +#define REG_TIMER_VALUE 0x004 +#define REG_TIMER_CONTROL 0x008 +#define REG_TIMER_INTCLR 0x00C +#define REG_TIMER_RIS 0x010 +#define REG_TIMER_MIS 0x014 +#define REG_TIMER_BGLOAD 0x018 + +#define REG_TIMER1_RELOAD 0x020 +#define REG_TIMER1_VALUE 0x024 +#define REG_TIMER1_CONTROL 0x028 +#define REG_TIMER1_INTCLR 0x02C +#define REG_TIMER1_RIS 0x030 +#define REG_TIMER1_MIS 0x034 +#define REG_TIMER1_BGLOAD 0x038 + + +#define REG_SC_REMAP 0x0204 + +#define REG_SYS_SOFT_RSTEN 0x80 +#define REG_SYS_SOFT_RST 0x84 +#define REG_CPU1_SOFT_RST 0x8C + +#define GPIO_MUX1_EN (1 << 1) +#define GPIO_MUX2_EN (1 << 2) +#define GPIO_MUX3_EN (1 << 3) +#define GPIO_OUT_EN (1 << 10) +#define GPIO_OUT_HIGH (1 << 11) +#define GPIO_OUT_LOW (0 << 11) +#define GPIO_IN_EN (1 << 12) +#define GPIO_DRIVE_2MA (0 << 6) +#define GPIO_DRIVE_4MA (1 << 6) +#define GPIO_DRIVE_8MA (2 << 6) +#define GPIO_DRIVE_12MA (3 << 6) + +#define GPIO_FLASH_CLK 9 +#define GPIO_FLASH_CSN 10 +#define GPIO_FLASH_DI 11 +#define GPIO_FLASH_DO 12 +#define GPIO_FLASH_WPN 13 +#define GPIO_FLASH_HOLD 14 + +#define SMP_COREX_START_ADDR_REG 0x20000F00/* see bootloader */ + +#endif diff -uarN a/arch/arm/mach-xm530/include/mach/time.h b/arch/arm/mach-xm530/include/mach/time.h --- a/arch/arm/mach-xm530/include/mach/time.h 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/include/mach/time.h 2018-11-22 14:05:13.000000000 +0300 @@ -0,0 +1,23 @@ +#ifndef ASM_XM_TIMER +#define ASM_XM_TIMER + +#define CFG_TIMER01_VABASE TIMER01_BASE +#define CFG_TIMER23_VABASE TIMER23_BASE + +#define CFG_TIMER_CONTROL (CFG_TIMER_ENABLE | CFG_TIMER_PERIODIC\ + | CFG_TIMER_INTMASK | CFG_TIMER_32BIT) +#define CFG_TIMER_ONE_CONTROL (CFG_TIMER_ENABLE | CFG_TIMER_INTMASK\ + | CFG_TIMER_32BIT | CFG_TIMER_ONESHOT) + +#define CFG_TIMER_ENABLE (1 << 7) +#define CFG_TIMER_PERIODIC (1 << 6) +#define CFG_TIMER_INTMASK (1 << 5) +#define CFG_TIMER_32BIT (1 << 1) +#define CFG_TIMER_ONESHOT (1 << 0) + +#define CFG_TIMER_CLK 24000000 + +#define CFG_TIMER_INTNR TIMER01_IRQ + +extern unsigned long long sched_clock(void); +#endif diff -uarN a/arch/arm/mach-xm530/include/mach/timex.h b/arch/arm/mach-xm530/include/mach/timex.h --- a/arch/arm/mach-xm530/include/mach/timex.h 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/include/mach/timex.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __XM_TIMEX__ +#define __XM_TIMEX__ + +#define CLOCK_TICK_RATE 24000000 + +#endif diff -uarN a/arch/arm/mach-xm530/include/mach/uncompress.h b/arch/arm/mach-xm530/include/mach/uncompress.h --- a/arch/arm/mach-xm530/include/mach/uncompress.h 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/include/mach/uncompress.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,38 @@ +#ifndef __XM_UNCOMPRESS_H__ +#define __XM_UNCOMPRESS_H__ +#include +#include + +#define AMBA_UART_DR \ + (*(volatile unsigned char *)(UART0_BASE + 0x0)) +#define AMBA_UART_LCRH \ + (*(volatile unsigned char *)(UART0_BASE + 0x2c)) +#define AMBA_UART_CR \ + (*(volatile unsigned char *)(UART0_BASE + 0x30)) +#define AMBA_UART_FR \ + (*(volatile unsigned char *)(UART0_BASE + 0x18)) + +/* + * This does not append a newline + */ +static inline void putc(int c) +{ + while (AMBA_UART_FR & (1 << 5)) + barrier(); + + AMBA_UART_DR = c; +} + +static inline void flush(void) +{ + while (AMBA_UART_FR & (1 << 3)) + barrier(); +} + +/* + * nothing to do + */ +#define arch_decomp_setup() +#define arch_decomp_wdog() + +#endif diff -uarN a/arch/arm/mach-xm530/include/mach/vmalloc.h b/arch/arm/mach-xm530/include/mach/vmalloc.h --- a/arch/arm/mach-xm530/include/mach/vmalloc.h 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/include/mach/vmalloc.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __XM_VMALLOC_H__ +#define __XM_VMALLOC_H__ + +#define VMALLOC_END (PAGE_OFFSET + 0x3e000000) + +#endif diff -uarN a/arch/arm/mach-xm530/l2cache.c b/arch/arm/mach-xm530/l2cache.c --- a/arch/arm/mach-xm530/l2cache.c 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/l2cache.c 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,117 @@ +/****************************************************************************** + * COPYRIGHT (C) 2013 Hisilicon + * All rights reserved. + * *** + * Create by Czyong 2013-12-19 + * +******************************************************************************/ + +#define pr_fmt(fmt) "l2cache: " fmt + +#include +#include +#include +#include +#include + +#include "l2cache.h" + +static void __iomem *l2x0_virt_base = __io_address(REG_BASE_L2CACHE); + +struct l2cache_data_t { + u32 aux; + u32 latency; + u32 prefetch; +}; + +/*****************************************************************************/ + +//#ifdef CONFIG_PM +#if 0 +static struct l2cache_data_t l2cache_data; + +/* + * hi_pm_disable_l2cache()/hi_pm_enable_l2cache() is designed to + * disable and enable l2-cache during Suspend-Resume phase + */ +int hi_pm_disable_l2cache(void) +{ + /* backup aux control register value */ + l2cache_data.aux = readl_relaxed(l2x0_virt_base + L2X0_AUX_CTRL); + l2cache_data.latency = readl_relaxed(l2x0_virt_base + + L2X0_DATA_LATENCY_CTRL); + l2cache_data.prefetch = readl_relaxed(l2x0_virt_base + + L2X0_PREFETCH_CTRL); + + outer_flush_all(); + + /* disable l2x0 cache */ + writel_relaxed(0, l2x0_virt_base + L2X0_CTRL); + + /* barrier */ + dmb(); + + pr_info("l2x0 cache disabled.\r\n"); + + return 0; +} +/*****************************************************************************/ + +int hi_pm_enable_l2cache(void) +{ + /*enable dynamic clk gating and standby mode*/ + writel_relaxed((L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN), + (l2x0_virt_base + L2X0_POWER_CTRL)); + + /* disable cache */ + writel_relaxed(0, l2x0_virt_base + L2X0_CTRL); + + /* restore aux control register */ + writel_relaxed(l2cache_data.aux, l2x0_virt_base + L2X0_AUX_CTRL); + writel_relaxed(l2cache_data.latency, l2x0_virt_base + + L2X0_DATA_LATENCY_CTRL); + writel_relaxed(l2cache_data.prefetch, l2x0_virt_base + + L2X0_PREFETCH_CTRL); + + /* invalidate l2x0 cache */ + outer_inv_all(); + + /* enable l2x0 cache */ + writel_relaxed(1, l2x0_virt_base + L2X0_CTRL); + + mb(); + + return 0; +} +#endif /* CONFIG_PM */ +/*****************************************************************************/ + +static int __init l2_cache_init(void) +{ + /* + * Bits Value Description + * [31] 0 : SBZ + * [30] 1 : Double linefill enable (L3) + * [29] 1 : Instruction prefetching enable + * [28] 1 : Data prefetching enabled + * [27] 0 : Double linefill on WRAP read enabled (L3) + * [26:25] 0 : SBZ + * [24] 1 : Prefetch drop enable (L3) + * [23] 0 : Incr double Linefill enable (L3) + * [22] 0 : SBZ + * [21] 0 : Not same ID on exclusive sequence enable (L3) + * [20:5] 0 : SBZ + * [4:0] 0 : use the Prefetch offset values 0. + */ + writel_relaxed(0x71000000, l2x0_virt_base + L2X0_PREFETCH_CTRL); + + + //FPGA 配置0 正式芯片不用配置默认值777 + writel_relaxed(0, l2x0_virt_base + L2X0_TAG_LATENCY_CTRL); + writel_relaxed(0, l2x0_virt_base + L2X0_DATA_LATENCY_CTRL); + + l2x0_init(l2x0_virt_base, 0x00420000, 0xFFB0FFFF); + + return 0; +} +early_initcall(l2_cache_init); diff -uarN a/arch/arm/mach-xm530/l2cache.h b/arch/arm/mach-xm530/l2cache.h --- a/arch/arm/mach-xm530/l2cache.h 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/l2cache.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,21 @@ +/****************************************************************************** + * COPYRIGHT (C) 2013 Hisilicon + * All rights reserved. + * *** + * Create by Czyong 2013-12-19 + * +******************************************************************************/ +#ifndef L2CACHEH +#define L2CACHEH +/******************************************************************************/ + +#ifdef CONFIG_CACHE_L2X0 +extern int xm_pm_disable_l2cache(void); +extern int xm_pm_enable_l2cache(void); +#else +# define xm_pm_disable_l2cache() +# define xm_pm_enable_l2cache() +#endif + +/******************************************************************************/ +#endif /* L2CACHEH */ diff -uarN a/arch/arm/mach-xm530/platsmp.c b/arch/arm/mach-xm530/platsmp.c --- a/arch/arm/mach-xm530/platsmp.c 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/platsmp.c 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,169 @@ +/****************************************************************************** + * COPYRIGHT (C) 2013 Hisilicon + * All rights reserved. + * *** + * Create by Czyong 2013-12-19 + * +******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "platsmp.h" +#include "hotplug.h" + +static DEFINE_SPINLOCK(boot_lock); + +/*****************************************************************************/ + +static void __cpuinit write_pen_release(int val) +{ + pen_release = val; + smp_wmb(); + __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); + outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); +} +/*****************************************************************************/ +static void __iomem *scu_base_addr(void) +{ + return __io_address(ARM_INTNL_BASE + REG_A5_PERI_SCU); +} + +static int __cpuinit xm530_boot_secondary(unsigned int cpu, + struct task_struct *idle) +{ + unsigned long timeout; + + + set_scu_boot_addr(0x00000000, + (unsigned int)virt_to_phys(xm530_secondary_startup)); + + /* + * set synchronisation state between this boot processor + * and the secondary one + */ + spin_lock(&boot_lock); + + xm530_scu_power_up(cpu); + + /* + * The secondary processor is waiting to be released from + * the holding pen - release it, then wait for it to flag + * that it has been released by resetting pen_release. + * + * Note that "pen_release" is the hardware CPU ID, whereas + * "cpu" is Linux's internal ID. + */ + write_pen_release(cpu); + + /* + * Send the secondary CPU a soft interrupt, thereby causing + * the boot monitor to read the system wide flags register, + * and branch to the address found there. + */ + arch_send_wakeup_ipi_mask(cpumask_of(cpu)); + /* + * Send the secondary CPU a soft interrupt, thereby causing + * the boot monitor to read the system wide flags register, + * and branch to the address found there. + */ + timeout = jiffies + (5 * HZ); + while (time_before(jiffies, timeout)) { + smp_rmb(); + if (pen_release == -1) + { + break; + } + udelay(10); + } + + /* + * now the secondary core is starting up let it run its + * calibrations, then wait for it to finish + */ + spin_unlock(&boot_lock); + return pen_release != -1 ? -ENOSYS : 0; +} +/*****************************************************************************/ + +static void __cpuinit xm530_secondary_init(unsigned int cpu) +{ + /* + * 1. enable L1 prefetch [2] + * 2. enable L2 prefetch hint [1]a + * 3. enable write full line of zeros mode. [3]a + * 4. enable allocation in one cache way only. [8] + * a: This feature must be enabled only when the slaves + * connected on the Cortex-A17 AXI master port support it. + */ + /* + asm volatile ( + " mrc p15, 0, r0, c1, c0, 1\n" + " orr r0, r0, #0x0104\n" + " orr r0, r0, #0x02\n" + " mcr p15, 0, r0, c1, c0, 1\n" + : + : + : "r0", "cc"); + */ + /* + * + * let the primary processor know we're out of the + * pen, then head off into the C entry point + */ + + write_pen_release(-1); + /* + * Synchronise with the boot thread. + */ + spin_lock(&boot_lock); + spin_unlock(&boot_lock); +} +/*****************************************************************************/ + +static void __init xm530_smp_init_cpus(void) +{ + void __iomem *scu_base = scu_base_addr(); + unsigned int i, ncores; + + ncores = scu_base ? scu_get_core_count(scu_base) : 1; + + /* sanity check */ + if (ncores > NR_CPUS) { + printk(KERN_WARNING + "Realview: no. of cores (%d) greater than configured " + "maximum of %d - clipping\n", + ncores, NR_CPUS); + ncores = NR_CPUS; + } + + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); +} +/*****************************************************************************/ + +static void __init xm530_smp_prepare_cpus(unsigned int max_cpus) +{ + scu_enable(scu_base_addr()); +} +/*****************************************************************************/ + +struct smp_operations xm530_smp_ops __initdata = { + .smp_init_cpus = xm530_smp_init_cpus, + .smp_prepare_cpus = xm530_smp_prepare_cpus, + .smp_secondary_init = xm530_secondary_init, + .smp_boot_secondary = xm530_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = xm530_cpu_die, +#endif +}; diff -uarN a/arch/arm/mach-xm530/platsmp.h b/arch/arm/mach-xm530/platsmp.h --- a/arch/arm/mach-xm530/platsmp.h 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/platsmp.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,17 @@ +/****************************************************************************** + * COPYRIGHT (C) 2013 Hisilicon + * All rights reserved. + * *** + * Create by Czyong 2013-12-19 + * +******************************************************************************/ +#ifndef __PLATSMP__H__ +#define __PLATSMP__H__ + +extern struct smp_operations xm530_smp_ops; + +void xm530_scu_power_up(int cpu); +void xm530_secondary_startup(void); + +#endif + diff -uarN a/arch/arm/mach-xm530/timer.c b/arch/arm/mach-xm530/timer.c --- a/arch/arm/mach-xm530/timer.c 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-xm530/timer.c 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,316 @@ +/****************************************************************************** + * COPYRIGHT (C) 2013 Czyong. Hisilicon + * All rights reserved. + * *** + * Create by Czyong 2013-03-12 + * +******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/*****************************************************************************/ + +struct xm_timer_t { + int init; /* timer initialize times */ + int index; /* timer index */ + char *name; + unsigned int addr; /* timer control base address */ + struct irqaction irq; + void *priv; +}; + +#define XM_TIMER(_index, _irq, _addr) { \ + .init = 0, \ + .index = _index, \ + .name = "timer"#_index, \ + .addr = IO_ADDRESS(_addr), \ + .priv = NULL, \ + .irq.irq = _irq,\ + .irq.name = "timer"#_index, \ + .irq.flags = (IRQF_TIMER | IRQF_NOBALANCING | IRQF_PERCPU), \ +} + +static struct xm_timer_t xm_timer[] = { + XM_TIMER(0, INTNR_TIMER_0, TIMER0_REG_BASE), + XM_TIMER(1, INTNR_TIMER_1, TIMER1_REG_BASE), + XM_TIMER(2, INTNR_TIMER_2, TIMER2_REG_BASE), + XM_TIMER(3, INTNR_TIMER_3, TIMER3_REG_BASE), +}; + +#define TIMER(_index) (&xm_timer[_index]) + +//#define GET_SMP_TIMER(_cpu) (&xm_timer[((_cpu) << 1) + 4]) +#define GET_SMP_TIMER(_cpu) (&xm_timer[(_cpu) + 2]) +/*****************************************************************************/ + +static long __init sp804_get_clock_rate(const char *name) +{ + struct clk *clk; + long rate; + int err; + + clk = clk_get_sys("sp804", name); + if (IS_ERR(clk)) { + pr_err("sp804: %s clock not found: %d\n", name, + (int)PTR_ERR(clk)); + return PTR_ERR(clk); + } + + err = clk_prepare(clk); + if (err) { + pr_err("sp804: %s clock failed to prepare: %d\n", name, err); + clk_put(clk); + return err; + } + + err = clk_enable(clk); + if (err) { + pr_err("sp804: %s clock failed to enable: %d\n", name, err); + clk_unprepare(clk); + clk_put(clk); + return err; + } + + rate = clk_get_rate(clk); + if (rate < 0) { + pr_err("sp804: %s clock failed to get rate: %ld\n", name, rate); + clk_disable(clk); + clk_unprepare(clk); + clk_put(clk); + } + + return rate; +} + +#if 0 + +static unsigned long local_timer_rate; + +static void sp804_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + struct xm_timer_t *timer = GET_SMP_TIMER(smp_processor_id()); + unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE; + unsigned int clkevt_base = timer->addr; + + writel(ctrl, IOMEM(clkevt_base + TIMER_CTRL)); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + writel(DIV_ROUND_CLOSEST(local_timer_rate, HZ), + IOMEM(clkevt_base + TIMER_LOAD)); + ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; + break; + + case CLOCK_EVT_MODE_ONESHOT: + /* period set, and timer enabled in 'next_event' hook */ + ctrl |= TIMER_CTRL_ONESHOT; + break; + + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + default: + break; + } + + writel(ctrl, IOMEM(clkevt_base + TIMER_CTRL)); +} + +static int sp804_set_next_event(unsigned long next, + struct clock_event_device *evt) +{ + struct xm_timer_t *timer = GET_SMP_TIMER(smp_processor_id()); + unsigned int clkevt_base = timer->addr; + unsigned long ctrl = readl(IOMEM(clkevt_base + TIMER_CTRL)); + + writel(next, IOMEM(clkevt_base + TIMER_LOAD)); + writel(ctrl | TIMER_CTRL_ENABLE, IOMEM(clkevt_base + TIMER_CTRL)); + + return 0; +} + +static irqreturn_t sp804_timer_isr(int irq, void *dev_id) +{ + struct xm_timer_t *timer = (struct xm_timer_t *)dev_id; + unsigned int clkevt_base = timer->addr; + struct clock_event_device *evt + = (struct clock_event_device *)timer->priv; + + /* clear the interrupt */ + writel(1, IOMEM(clkevt_base + TIMER_INTCLR)); + + evt->event_handler(evt); + + return IRQ_HANDLED; +} +/*****************************************************************************/ + +/* every should have it's timer irq. */ +static int __cpuinit xm530_local_timer_setup(struct clock_event_device *evt) +{ + unsigned int cpu = smp_processor_id(); + struct xm_timer_t *timer = GET_SMP_TIMER(cpu); + struct irqaction *irq = &timer->irq; + + + + evt->name = timer->name; + evt->irq = irq->irq; + evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT + | CLOCK_EVT_FEAT_C3STOP; + + evt->set_mode = sp804_set_mode; + evt->set_next_event = sp804_set_next_event; + evt->rating = 350; + + timer->priv = (void *)evt; + + clockevents_config_and_register(evt, local_timer_rate, 0xf, 0xffffffff); + irq_set_affinity(evt->irq, evt->cpumask); + enable_irq(evt->irq); + + + return 0; +} + +static void xm530_local_timer_stop(struct clock_event_device *evt) +{ + evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); + disable_irq(evt->irq); +} +/*****************************************************************************/ + +static struct local_timer_ops xm530_timer_tick_ops __cpuinitdata = { + .setup = xm530_local_timer_setup, + .stop = xm530_local_timer_stop, +}; + +static void __init xm530_local_timer_init(void) +{ + unsigned int cpu = 0; + unsigned int ncores = num_possible_cpus(); + + local_timer_rate = sp804_get_clock_rate("sp804"); + + for (cpu = 0; cpu < ncores; cpu++) { + struct xm_timer_t *cpu_timer = GET_SMP_TIMER(cpu); + cpu_timer->irq.handler = sp804_timer_isr; + cpu_timer->irq.dev_id = (void *)cpu_timer; + setup_irq(cpu_timer->irq.irq, &cpu_timer->irq); + disable_irq(cpu_timer->irq.irq); + } + + local_timer_register(&xm530_timer_tick_ops); +} +#endif + + +/*****************************************************************************/ +#ifdef CONFIG_LOCAL_TIMERS +DEFINE_TWD_LOCAL_TIMER(twd_localtimer, (resource_size_t)(ARM_INTNL_BASE + REG_A5_PERI_PRI_TIMER_WDT), (resource_size_t)IRQ_LOCALTIMER); +#endif + +/*****************************************************************************/ + +struct xm530_clocksource { + void __iomem *base; + struct clocksource clksrc; +}; + +static struct xm530_clocksource xm530_clocksource = {0}; + +static inline struct xm530_clocksource + *to_xm530_clksrc(struct clocksource *cs) +{ + return container_of(cs, struct xm530_clocksource, clksrc); +} + +static void xm530_clocksource_start(void __iomem *base) +{ + writel(0, IOMEM(base + TIMER_CTRL)); + writel(0xffffffff, IOMEM(base + TIMER_LOAD)); + writel(0xffffffff, IOMEM(base + TIMER_VALUE)); + writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC, + IOMEM(base + TIMER_CTRL)); +} + +static cycle_t xm530_clocksource_read(struct clocksource *cs) +{ + return ~readl_relaxed(to_xm530_clksrc(cs)->base + TIMER_VALUE); +} + +static notrace u32 xm530_sched_clock_read(void) +{ + return ~readl_relaxed(xm530_clocksource.base + TIMER_VALUE); +} + +static void xm530_clocksource_resume(struct clocksource *cs) +{ + xm530_clocksource_start(to_xm530_clksrc(cs)->base); +} + +static void __init xm530_clocksource_init(void __iomem *base, + const char *name) +{ + long rate = sp804_get_clock_rate(name); + struct clocksource *clksrc = &xm530_clocksource.clksrc; + + if (rate < 0) + return; + + clksrc->name = name; + clksrc->rating = 200; + clksrc->read = xm530_clocksource_read; + clksrc->mask = CLOCKSOURCE_MASK(32), + clksrc->flags = CLOCK_SOURCE_IS_CONTINUOUS, + clksrc->resume = xm530_clocksource_resume, + + xm530_clocksource.base = base; + + xm530_clocksource_start(base); + + clocksource_register_hz(clksrc, rate); + + setup_sched_clock(xm530_sched_clock_read, 32, rate); +} + + +void __init xm530_timer_init(void) +{ + + /* set the bus clock for all timer */ + +#ifdef CONFIG_LOCAL_TIMERS + //xm530_local_timer_init(); + twd_local_timer_register(&twd_localtimer); +#endif + + xm530_clocksource_init((void *)TIMER(0)->addr, + TIMER(0)->name); + + sp804_clockevents_init((void *)TIMER(1)->addr, + TIMER(1)->irq.irq, TIMER(1)->name); + +} + diff -uarN a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types --- a/arch/arm/tools/mach-types 2016-08-28 13:19:20.000000000 +0300 +++ b/arch/arm/tools/mach-types 2018-12-06 05:52:16.000000000 +0300 @@ -1007,3 +1007,4 @@ eukrea_cpuimx28sd MACH_EUKREA_CPUIMX28SD EUKREA_CPUIMX28SD 4573 domotab MACH_DOMOTAB DOMOTAB 4574 pfla03 MACH_PFLA03 PFLA03 4575 +xm530 MACH_XM530 XM530 8888 diff -uarN a/drivers/dma/pl330.c b/drivers/dma/pl330.c --- a/drivers/dma/pl330.c 2016-08-28 13:19:20.000000000 +0300 +++ b/drivers/dma/pl330.c 2018-11-21 06:44:38.000000000 +0300 @@ -655,10 +655,10 @@ void __iomem *regs = pi->base; u32 id = 0; - id |= (readb(regs + off + 0x0) << 0); - id |= (readb(regs + off + 0x4) << 8); - id |= (readb(regs + off + 0x8) << 16); - id |= (readb(regs + off + 0xc) << 24); + id |= (readl(regs + off + 0x0) << 0); + id |= (readl(regs + off + 0x4) << 8); + id |= (readl(regs + off + 0x8) << 16); + id |= (readl(regs + off + 0xc) << 24); return id; } diff -uarN a/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c 2016-08-28 13:19:20.000000000 +0300 +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c 1970-01-01 03:00:00.000000000 +0300 @@ -1,100 +0,0 @@ -/* - * Copyright 2009 Red Hat Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Ben Skeggs - */ - -#include - -int -nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size) -{ - if (port->func->aux) { - if (port->func->acquire) - port->func->acquire(port); - return port->func->aux(port, 9, addr, data, size); - } - return -ENODEV; -} - -int -nv_wraux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size) -{ - if (port->func->aux) { - if (port->func->acquire) - port->func->acquire(port); - return port->func->aux(port, 8, addr, data, size); - } - return -ENODEV; -} - -static int -aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) -{ - struct nouveau_i2c_port *port = adap->algo_data; - struct i2c_msg *msg = msgs; - int ret, mcnt = num; - - if (!port->func->aux) - return -ENODEV; - if ( port->func->acquire) - port->func->acquire(port); - - while (mcnt--) { - u8 remaining = msg->len; - u8 *ptr = msg->buf; - - while (remaining) { - u8 cnt = (remaining > 16) ? 16 : remaining; - u8 cmd; - - if (msg->flags & I2C_M_RD) - cmd = 1; - else - cmd = 0; - - if (mcnt || remaining > 16) - cmd |= 4; /* MOT */ - - ret = port->func->aux(port, cmd, msg->addr, ptr, cnt); - if (ret < 0) - return ret; - - ptr += cnt; - remaining -= cnt; - } - - msg++; - } - - return num; -} - -static u32 -aux_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; -} - -const struct i2c_algorithm nouveau_i2c_aux_algo = { - .master_xfer = aux_xfer, - .functionality = aux_func -}; diff -uarN a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c --- a/drivers/media/v4l2-core/videobuf2-core.c 2016-08-28 13:19:20.000000000 +0300 +++ b/drivers/media/v4l2-core/videobuf2-core.c 2019-02-14 05:41:45.000000000 +0300 @@ -1370,7 +1370,7 @@ /* Fill buffer information for the userspace */ __fill_v4l2_buffer(vb, b); - dprintk(1, "qbuf of buffer %d succeeded\n", vb->v4l2_buf.index); + //dprintk(1, "qbuf of buffer %d succeeded\n", vb->v4l2_buf.index); unlock: if (mmap_sem) up_read(mmap_sem); @@ -1588,8 +1588,8 @@ /* go back to dequeued state */ __vb2_dqbuf(vb); - dprintk(1, "dqbuf of buffer %d, with state %d\n", - vb->v4l2_buf.index, vb->state); + //dprintk(1, "dqbuf of buffer %d, with state %d\n", + // vb->v4l2_buf.index, vb->state); return 0; } @@ -1985,12 +1985,15 @@ res = POLLPRI; else if (req_events & POLLPRI) poll_wait(file, &fh->wait, wait); + } - if (!V4L2_TYPE_IS_OUTPUT(q->type) && !(req_events & (POLLIN | POLLRDNORM))) + if (!V4L2_TYPE_IS_OUTPUT(q->type) && !(req_events & (POLLIN | POLLRDNORM))) { return res; - if (V4L2_TYPE_IS_OUTPUT(q->type) && !(req_events & (POLLOUT | POLLWRNORM))) + } + if (V4L2_TYPE_IS_OUTPUT(q->type) && !(req_events & (POLLOUT | POLLWRNORM))) { return res; + } /* * Start file I/O emulator only if streaming API has not been used yet. @@ -1998,13 +2001,15 @@ if (q->num_buffers == 0 && q->fileio == NULL) { if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ) && (req_events & (POLLIN | POLLRDNORM))) { - if (__vb2_init_fileio(q, 1)) + if (__vb2_init_fileio(q, 1)) { return res | POLLERR; + } } if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE) && (req_events & (POLLOUT | POLLWRNORM))) { - if (__vb2_init_fileio(q, 0)) + if (__vb2_init_fileio(q, 0)) { return res | POLLERR; + } /* * Write to OUTPUT queue can be done immediately. */ @@ -2015,15 +2020,17 @@ /* * There is nothing to wait for if the queue isn't streaming. */ - if (!vb2_is_streaming(q)) - return res | POLLERR; + if (!vb2_is_streaming(q)) { + return res /* | POLLERR */; + } /* * For compatibility with vb1: if QBUF hasn't been called yet, then * return POLLERR as well. This only affects capture queues, output * queues will always initialize waiting_for_buffers to false. */ - if (q->waiting_for_buffers) + if (q->waiting_for_buffers) { return res | POLLERR; + } if (list_empty(&q->done_list)) poll_wait(file, &q->done_wq, wait); @@ -2043,6 +2050,7 @@ res | POLLOUT | POLLWRNORM : res | POLLIN | POLLRDNORM; } + return res; } EXPORT_SYMBOL_GPL(vb2_poll); diff -uarN a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c --- a/drivers/mmc/core/mmc.c 2016-08-28 13:19:20.000000000 +0300 +++ b/drivers/mmc/core/mmc.c 2018-11-21 06:44:38.000000000 +0300 @@ -296,7 +296,8 @@ } card->ext_csd.rev = ext_csd[EXT_CSD_REV]; - if (card->ext_csd.rev > 6) { + //if (card->ext_csd.rev > 6) { + if (card->ext_csd.rev > 8) { pr_err("%s: unrecognised EXT_CSD revision %d\n", mmc_hostname(card->host), card->ext_csd.rev); err = -EINVAL; diff -uarN a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig --- a/drivers/mmc/host/Kconfig 2016-08-28 13:19:20.000000000 +0300 +++ b/drivers/mmc/host/Kconfig 2018-11-21 06:44:38.000000000 +0300 @@ -4,6 +4,23 @@ comment "MMC/SD/SDIO Host Controller Drivers" +config MMC_ARASAN + tristate "Arasan MMC/SD/SDIO host driver" + help + This selects the Arasan MMC/SD/SDIO host controller integrated + in the xm platform. + +config MMC_WIFI + tristate "WIFI" + help + This selects the WIFI integrated + in the xm platform. +config MMC_SD + tristate "SD-CARD" + help + This selects the SD-CARD integrated + in the xm platform. + config MMC_ARMMMCI tristate "ARM AMBA Multimedia Card Interface support" depends on ARM_AMBA @@ -547,6 +564,13 @@ If unsure, say Y. +config MMC_DW_XM + tristate "dw mmc xm hardware " + depends on MMC_DW + default y + help + This selects support for xm hardware. + config MMC_DW_EXYNOS tristate "Exynos specific extensions for Synopsys DW Memory Card Interface" depends on MMC_DW diff -uarN a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile --- a/drivers/mmc/host/Makefile 2016-08-28 13:19:20.000000000 +0300 +++ b/drivers/mmc/host/Makefile 2018-11-21 06:44:38.000000000 +0300 @@ -2,6 +2,9 @@ # Makefile for MMC/SD host controller drivers # +obj-$(CONFIG_MMC_ARASAN) += arasan.o +obj-$(CONFIG_MMC_WIFI) += sdio1_wifi.o +obj-$(CONFIG_MMC_SD) += sdio0_sd.o obj-$(CONFIG_MMC_ARMMMCI) += mmci.o obj-$(CONFIG_MMC_PXA) += pxamci.o obj-$(CONFIG_MMC_MXC) += mxcmmc.o @@ -40,6 +43,7 @@ obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o obj-$(CONFIG_MMC_DW) += dw_mmc.o +obj-$(CONFIG_MMC_DW_XM) += dw_mmc_xm_device.o obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o diff -uarN a/drivers/mmc/host/arasan.c b/drivers/mmc/host/arasan.c --- a/drivers/mmc/host/arasan.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/mmc/host/arasan.c 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,1719 @@ +/* + * Arasan MMC/SD/SDIO driver + * + * This is the driver for the Arasan MMC/SD/SDIO host controller + * integrated in the STMicroelectronics platforms + * + * Author: Giuseppe Cavallaro + * Copyright (C) 2010 STMicroelectronics Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "arasan.h" + +/* To enable more debug information. */ +//#define ARASAN_DEBUG +//#define DEBUG + +#ifdef ARASAN_DEBUG +#define DBG(fmt, args...) pr_info(fmt, ## args) +#else +#define DBG(fmt, args...) do { } while (0) +#endif + +static int maxfreq = ARASAN_CLOCKRATE_MAX; +//module_param(maxfreq, int, S_IRUGO); +//MODULE_PARM_DESC(maxfreq, "Maximum card clock frequency (default 25MHz)"); + +static unsigned int adma = 1; +//module_param(adma, int, S_IRUGO); +//MODULE_PARM_DESC(adma, "Disable/Enable the Advanced DMA mode"); + +static unsigned int led; +//module_param(led, int, S_IRUGO | S_IWUSR); +//MODULE_PARM_DESC(led, "Enable|Disable LED"); + +//static unsigned int pio; +//module_param(pio, int, S_IRUGO); +//MODULE_PARM_DESC(pio, "PIO mode (no DMA)"); + +struct arasan_cap { + unsigned int timer_freq; + unsigned int timer_unit; + unsigned int base_clk_sd; + unsigned int max_blk_len; + unsigned int adma2; + unsigned int high_speed; + unsigned int sdma; + unsigned int suspend; + unsigned int voltage33; + unsigned int voltage30; + unsigned int voltage18; + unsigned int int_mode; + unsigned int spi; + unsigned int spi_block; +}; + +struct arasan_host { + void __iomem *base; + struct mmc_request *mrq; + unsigned int intr_en; + u8 ctrl; + unsigned int sg_frags; + struct scatterlist **sg; + struct timer_list timer; + struct mmc_host *mmc; + struct device *dev; + struct resource *res; + int irq; + struct arasan_cap cap; + u8 vdd; + unsigned int freq; + unsigned int status; + unsigned int adma; + unsigned int use_pio; + u16 pio_blksz; + u32 pio_blocks; + u32 *pio_blkbuf; + spinlock_t lock; + struct tasklet_struct card_tasklet; + u8 *adma_desc; + dma_addr_t adma_addr; + + unsigned int need_poll; + unsigned int need_detect; + unsigned int card_irq; + unsigned int auto_cmd12; + unsigned int sdio_4bit_data; +}; + +static inline void arsan_sw_reset(struct arasan_host *host, unsigned int flag) +{ + /* After completing the reset, wait the HC clears these bits */ + if (likely(flag == reset_all)) { + writeb(ARSAN_RESET_ALL, host->base + ARASAN_SW_RESET); + do { } while ((readb(host->base + ARASAN_SW_RESET)) & + ARSAN_RESET_ALL); + } else if (flag == reset_cmd_line) { + writeb(ARSAN_RESET_CMD_LINE, host->base + ARASAN_SW_RESET); + do { } while ((readb(host->base + ARASAN_SW_RESET)) & + ARSAN_RESET_CMD_LINE); + + } else if (flag == reset_dat_line) { + writeb(ARSAN_RESET_DAT_LINE, host->base + ARASAN_SW_RESET); + do { } while ((readb(host->base + ARASAN_SW_RESET)) & + ARSAN_RESET_DAT_LINE); + } +} + +static inline void arsan_hc_version(struct arasan_host *host) +{ + u16 version; + + version = readw(host->base + ARASAN_HOST_VERSION); + DBG("Arasan MMC/SDIO:\n\tHC Vendor Version Number: %d\n", + (version >> 8)); + DBG("\tHC SPEC Version Number: %d\n", (version & 0x00ff)); +} + +static void arasan_capabilities(struct arasan_host *host) +{ + unsigned int cap; + unsigned int max_blk_len; + + cap = readl(host->base + ARASAN_CAPABILITIES); + + DBG("\tArasan capabilities: 0x%x\n", cap); + + host->cap.timer_freq = cap & 0x3f; + host->cap.timer_unit = (cap >> 7) & 0x1; + + DBG("\tTimeout Clock Freq: %d %s\n", host->cap.timer_freq, + host->cap.timer_unit ? "MHz" : "KHz"); + + host->cap.base_clk_sd = (cap >> 8) & 0x3f; + DBG("\tBase Clock Freq for SD: %d MHz\n", host->cap.base_clk_sd); + + max_blk_len = (cap >> 16) & 0x3; + switch (max_blk_len) { + case 0: + host->cap.max_blk_len = 512; + break; + case 1: + host->cap.max_blk_len = 1024; + break; + case 2: + host->cap.max_blk_len = 2048; + break; + case 3: + host->cap.max_blk_len = 4096; + break; + default: + break; + } + DBG("\tMax Block size: %d bytes\n", host->cap.max_blk_len); + //printk("\tMax Block size: %d bytes\n", host->cap.max_blk_len); + + host->cap.adma2 = (cap >> 19) & 0x1; + host->cap.high_speed = (cap >> 21) & 0x1; + host->cap.sdma = (cap >> 22) & 0x1; + + DBG("\tadma2 %s, high speed %s, sdma %s\n", + host->cap.adma2 ? "Yes" : "Not", + host->cap.high_speed ? "Yes" : "Not", + host->cap.sdma ? "Yes" : "Not"); + + host->cap.suspend = (cap >> 23) & 0x1; + DBG("\tsuspend/resume %s suported\n", + host->cap.adma2 ? "is" : "Not"); + + /* Disable adma user option if cap not supported. */ + if (!host->cap.adma2) + adma = 0; + + host->cap.voltage33 = (cap >> 24) & 0x1; + host->cap.voltage30 = (cap >> 25) & 0x1; + host->cap.voltage18 = (cap >> 26) & 0x1; + host->cap.int_mode = (cap >> 27) & 0x1; + host->cap.spi = (cap >> 29) & 0x1; /* 是否支持spi模式 */ + host->cap.spi_block = (cap >> 30) & 0x1; + + if (host->cap.voltage33) + DBG("\t3.3V voltage suported\n"); + if (host->cap.voltage30) + DBG("\t3.0V voltage suported\n"); + if (host->cap.voltage18) + DBG("\t1.8V voltage suported\n"); + + if (host->cap.int_mode) + DBG("\tInterrupt Mode supported\n"); + if (host->cap.spi) + DBG("\tSPI Mode supported\n"); + if (host->cap.spi_block) + DBG("\tSPI Block Mode supported\n"); +} + +static void arasan_ctrl_led(struct arasan_host *host, unsigned int flag) +{ + //printk(KERN_EMERG"arasan_ctrl_led.\n"); + if (led) { + u8 ctrl_reg = readb(host->base + ARASAN_HOST_CTRL); + + //printk(KERN_EMERG"flag:%d\n", flag); + if (flag) + ctrl_reg |= ARASAN_HOST_CTRL_LED; + else + ctrl_reg &= ~ARASAN_HOST_CTRL_LED; + + host->ctrl = ctrl_reg; + writeb(host->ctrl, host->base + ARASAN_HOST_CTRL); + } +} + +static inline void arasan_set_interrupts(struct arasan_host *host) +{ + host->intr_en = ARASAN_IRQ_DEFAULT_MASK; + writel(host->intr_en, host->base + ARASAN_NORMAL_INT_STATUS_EN); + writel(host->intr_en, host->base + ARASAN_NORMAL_INT_SIGN_EN); + +} + +static inline void arasan_clear_interrupts(struct arasan_host *host) +{ + writel(0, host->base + ARASAN_NORMAL_INT_STATUS_EN); + writel(0, host->base + ARASAN_ERR_INT_STATUS_EN); + writel(0, host->base + ARASAN_NORMAL_INT_SIGN_EN); +} + +static void arasan_power_set(struct arasan_host *host, unsigned int pwr, u8 vdd) +{ + u8 pwr_reg; + + pwr_reg = readb(host->base + ARASAN_PWR_CTRL); + + host->vdd = (1 << vdd); + + if (pwr) { + pwr_reg &= 0xf1; + + if ((host->vdd & MMC_VDD_165_195) && host->cap.voltage18) + pwr_reg |= ARASAN_PWR_BUS_VOLTAGE_18; + else if ((host->vdd & MMC_VDD_29_30) && host->cap.voltage30) + pwr_reg |= ARASAN_PWR_BUS_VOLTAGE_30; + else if ((host->vdd & MMC_VDD_32_33) && host->cap.voltage33) + pwr_reg |= ARASAN_PWR_BUS_VOLTAGE_33; + + //pwr_reg |= ARASAN_PWR_CTRL_UP; + /* 注意:电路设计和外围电路设计相反 */ + pwr_reg &= ~ARASAN_PWR_CTRL_UP; + } else + //pwr_reg &= ~ARASAN_PWR_CTRL_UP; + pwr_reg |= ARASAN_PWR_CTRL_UP; + + DBG("%s: pwr_reg 0x%x, host->vdd = 0x%x\n", __func__, pwr_reg, + host->vdd); + //printk(KERN_EMERG"pwr_reg:%2x\n", pwr_reg); + writeb(pwr_reg, host->base + ARASAN_PWR_CTRL); +} + +static int arasan_test_card(struct arasan_host *host) +{ + unsigned int ret = 0; + u32 present = readl(host->base + ARASAN_PRESENT_STATE); + + if (!host->need_detect) + goto out; + if (likely(!(present & ARASAN_PRESENT_STATE_CARD_PRESENT))) { + ret = -1; + } + +out: +#ifdef ARASAN_DEBUG + if (present & ARASAN_PRESENT_STATE_CARD_STABLE) + pr_info("\tcard stable..."); + if (!(present & ARASAN_PRESENT_STATE_WR_EN)) + pr_info("\tcard Write protected..."); + if (present & ARASAN_PRESENT_STATE_BUFFER_RD_EN) + pr_info("\tPIO Read Enable..."); + if (present & ARASAN_PRESENT_STATE_BUFFER_WR_EN) + pr_info("\tPIO Write Enable..."); + if (present & ARASAN_PRESENT_STATE_RD_ACTIVE) + pr_info("\tRead Xfer data..."); + if (present & ARASAN_PRESENT_STATE_WR_ACTIVE) + pr_info("\tWrite Xfer data..."); + if (present & ARASAN_PRESENT_STATE_DAT_ACTIVE) + pr_info("\tDAT line active..."); +#endif + return ret; +} +static void arasan_set_clock(struct arasan_host *host, unsigned int freq) +{ + u16 clock = 0; + unsigned long flags; + + /* 协商阶段400K-低速模式 */ + spin_lock_irqsave(&host->lock, flags); + + if ((host->freq != freq) && (freq)) { + u16 divisor; + + /* Ensure clock is off before making any changes */ + //writew(clock, host->base + ARASAN_CLOCK_CTRL); + + /* core checks if this is a good freq < max_freq */ + host->freq = freq; + + printk("%s:\n\tnew freq %d", __func__, host->freq); + + /* Work out divisor for specified clock frequency */ + for (divisor = 1; divisor <= 256; divisor *= 2) + /* Find first divisor producing a frequency less + * than or equal to MHz */ + if ((maxfreq / divisor) <= freq) + break; + + DBG("\tdivisor %d", divisor); + // printk("\tdivisor %d\n", divisor); + /* Set the clock divisor and enable the internal clock */ + clock = divisor << (ARASAN_CLOCK_CTRL_SDCLK_SHIFT); + //clock = 0 << (ARASAN_CLOCK_CTRL_SDCLK_SHIFT); + clock &= ARASAN_CLOCK_CTRL_SDCLK_MASK; + clock |= ARASAN_CLOCK_CTRL_ICLK_ENABLE; + writew(clock, host->base + ARASAN_CLOCK_CTRL); + // printk("\tread divisor %x\n", readw(host->base + ARASAN_CLOCK_CTRL)); + + /* Busy wait for the clock to become stable */ + do { } while (((readw(host->base + ARASAN_CLOCK_CTRL)) & + ARASAN_CLOCK_CTRL_ICLK_STABLE) == 0); + + /* Enable the SD clock */ + clock |= ARASAN_CLOCK_CTRL_SDCLK_ENABLE; + writew(clock, host->base + ARASAN_CLOCK_CTRL); + + DBG("\tclk ctrl reg. [0x%x]\n", + (unsigned int)readw(host->base + ARASAN_CLOCK_CTRL)); + } + + spin_unlock_irqrestore(&host->lock, flags); +} + +/* Read the response from the card */ +static void arasan_get_resp(struct mmc_command *cmd, struct arasan_host *host) +{ + unsigned int i; + unsigned int resp[4]; + + for (i = 0; i < 4; i++) + resp[i] = readl(host->base + ARASAN_RSP(i)); + + if (cmd->flags & MMC_RSP_136) { + cmd->resp[3] = (resp[0] << 8); + cmd->resp[2] = (resp[0] >> 24) | (resp[1] << 8); + cmd->resp[1] = (resp[1] >> 24) | (resp[2] << 8); + cmd->resp[0] = (resp[2] >> 24) | (resp[3] << 8); + } else { + cmd->resp[0] = resp[0]; + cmd->resp[1] = resp[1]; + } + + /* 数据出错之后,response寄存器当中仍然会有接收到响应数据 */ + //printk("resp[0]:%x\n",resp[0]); + + DBG("%s: resp length %s\n-(CMD%u):\n %08x %08x %08x %08x\n" + "-RAW reg:\n %08x %08x %08x %08x\n", + __func__, (cmd->flags & MMC_RSP_136) ? "136" : "48", cmd->opcode, + cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], + resp[0], resp[1], resp[2], resp[3]); +} + +int blocks; +static void arasan_read_block_pio(struct arasan_host *host) +{ + unsigned long flags; + u16 blksz; + + DBG("\tPIO reading\n"); + + local_irq_save(flags); + + for (blksz = host->pio_blksz; blksz > 0; blksz -= 4) { + + *host->pio_blkbuf = + readl(host->base + ARASAN_BUFF); + host->pio_blkbuf++; + } + + local_irq_restore(flags); +} + +static void arasan_write_block_pio(struct arasan_host *host) +{ + unsigned long flags; + u16 blksz; + + DBG("\tPIO writing\n"); + //printk("\tPIO writing\n"); + local_irq_save(flags); + + //printk("host->pio_blksize:%d\n", host->pio_blksz); + for (blksz = host->pio_blksz; blksz > 0; blksz -= 4) { + //writel(0x00,host->base + ARASAN_BUFF); + + writel(*host->pio_blkbuf, + host->base + ARASAN_BUFF); + host->pio_blkbuf++; + } + + local_irq_restore(flags); +} + +static void arasan_data_pio(struct arasan_host *host) +{ + static int i = 0; + static int j = 0; + int sg_length = 0; + static int size = 0; + static int size1 = 0; + if (host->pio_blocks == 0) + return; + + + if (host->status == STATE_DATA_READ) { + host->pio_blkbuf = sg_virt(host->sg[i])+size; + sg_length = sg_dma_len(host->sg[i]); + //printk("rd-%d, %d, %p, %d\n", host->sg_frags, i, host->pio_blkbuf, sg_length); + + while (readl(host->base + ARASAN_PRESENT_STATE) & + ARASAN_PRESENT_STATE_BUFFER_RD_EN) { + + arasan_read_block_pio(host); + + size += host->pio_blksz; + //printk("size:%d\n", size); + if (size == sg_length) { + /* 下个sg */ + i++; + size = 0; + + if (i==host->sg_frags) { + //printk("hello world.\n"); + host->pio_blocks--; + if (unlikely(host->pio_blocks != 0)) { + printk("SD-MMC fatal error.\n"); + } + i = 0; + /* 数据全部操作完 */ + if (host->sg) + kfree(host->sg); + break; + } + host->pio_blkbuf = sg_virt(host->sg[i]); + sg_length = sg_dma_len(host->sg[i]); + //printk("rd-%d, %d, %p, %d\n", host->sg_frags, i, host->pio_blkbuf, sg_length); + } + + host->pio_blocks--; + if (host->pio_blocks == 0) + break; + } + //printk("rd-sg_frags:%d, cur:%d\n", host->sg_frags, i); + + } else { + host->pio_blkbuf = sg_virt(host->sg[j])+size1; + sg_length = sg_dma_len(host->sg[j]); + //printk("wr-%d, %d, %p, %d\n", host->sg_frags, j, host->pio_blkbuf, sg_length); + while (readl(host->base + ARASAN_PRESENT_STATE) & + ARASAN_PRESENT_STATE_BUFFER_WR_EN) { + + arasan_write_block_pio(host); + + size1 += host->pio_blksz; + if (size1 == sg_length) { + /* 下个sg */ + j++; + size1 = 0; + + if (j==host->sg_frags) { + //printk("hello world.\n"); + host->pio_blocks--; + if (unlikely(host->pio_blocks != 0)) { + printk("SD-MMC fatal error.\n"); + } + j = 0; + + /* 数据全部操作完 */ + if (host->sg) + kfree(host->sg); + break; + } + host->pio_blkbuf = sg_virt(host->sg[j]); + sg_length = sg_dma_len(host->sg[j]); + //printk("dwr-%d, %d, %p, %d, %d\n", host->sg_frags, j, host->pio_blkbuf, sg_length, size1); + } + + host->pio_blocks--; + if (host->pio_blocks == 0) + break; + } + //printk("wr-%d, %d, %p, %d, %d\n", host->sg_frags, j, host->pio_blkbuf, sg_length, size1); + //printk("wr-sg_frags:%d, cur:%d\n", host->sg_frags, j); + } + + DBG("\tPIO transfer complete.\n"); +} + +static void arasan_start_cmd(struct arasan_host *host, struct mmc_command *cmd) +{ + u16 cmdreg = 0; + + /* Command Request */ + cmdreg = ARASAN_CMD_INDEX(cmd->opcode); + DBG("%s: cmd type %04x, CMD%d\n", __func__, + mmc_resp_type(cmd), cmd->opcode); + + if (cmd->flags & MMC_RSP_BUSY) { + cmdreg |= ARASAN_CMD_RSP_48BUSY; + DBG("\tResponse length 48 check Busy.\n"); + } else if (cmd->flags & MMC_RSP_136) { + cmdreg |= ARASAN_CMD_RSP_136; + DBG("\tResponse length 136\n"); + } else if (cmd->flags & MMC_RSP_PRESENT) { + cmdreg |= ARASAN_CMD_RSP_48; + DBG("\tResponse length 48\n"); + } else { + cmdreg |= ARASAN_CMD_RSP_NONE; + DBG("\tNo Response\n"); + } + + if (cmd->flags & MMC_RSP_CRC) { + cmdreg |= ARASAN_CMD_CHECK_CMDCRC; + DBG("\tCheck the CRC field in the response\n"); + } + if (cmd->flags & MMC_RSP_OPCODE) { + cmdreg |= ARASAN_CMD_INDX_CHECK; + DBG("\tCheck the Index field in the response\n"); + } + + /* Wait until the CMD line is not in use */ + do { } while ((readl(host->base + ARASAN_PRESENT_STATE)) & + ARASAN_PRESENT_STATE_CMD_INHIBIT); + + /* Set the argument register */ + writel(cmd->arg, host->base + ARASAN_ARG); + + /* Data present and must be transferred */ + if (likely(host->mrq->data)) { + cmdreg |= ARASAN_CMD_DATA_PRESENT; + if (cmd->flags & MMC_RSP_BUSY) + /* Wait for data inhibit */ + do { } while ((readl(host->base + + ARASAN_PRESENT_STATE)) & + ARASAN_PRESENT_STATE_DAT_INHIBIT); + } + + /* Write the Command */ + writew(cmdreg, host->base + ARASAN_CMD); + + DBG("\tcmd: 0x%x cmd reg: 0x%x - cmd->arg 0x%x, reg 0x%x\n", + cmdreg, readw(host->base + ARASAN_CMD), cmd->arg, + readl(host->base + ARASAN_ARG)); +} + +#ifdef ARASAN_DEBUG +static void arasan_adma_error(struct arasan_host *host) +{ + u8 status = readb(host->base + ARASAN_ADMA_ERR_STATUS); + + if (status & ARASAN_ADMA_ERROR_LENGTH) + pr_err("-ADMA Length Mismatch Error..."); + + if (status & ARASAN_ADMA_ERROR_ST_TFR) + pr_err("-Transfer Data Error desc: "); + else if (status & ARASAN_ADMA_ERROR_ST_FDS) + pr_err("-Fetch Data Error desc: "); + else if (status & ARASAN_ADMA_ERROR_ST_STOP) + pr_err("-Stop DMA Data Error desc: "); + + pr_err("0x%x", readl(host->base + ARASAN_ADMA_ADDRESS)); +} + +static void arasan_adma_dump_desc(u8 *desc) +{ + __le32 *dma; + __le16 *len; + u8 attr; + + pr_info("\tDescriptors:"); + + while (1) { + dma = (__le32 *) (desc + 4); + len = (__le16 *) (desc + 2); + attr = *desc; + + pr_info("\t\t%p: Buff 0x%08x, len %d, Attr 0x%02x\n", + desc, le32_to_cpu(*dma), le16_to_cpu(*len), attr); + + desc += 8; + + if (attr & 2) /* END of descriptor */ + break; + } +} +#else +static void arasan_adma_error(struct arasan_host *host) +{ +} + +static void arasan_adma_dump_desc(u8 *desc) +{ +} +#endif + +static int arasan_init_sg(struct arasan_host *host) +{ + + host->adma_desc = kmalloc((ARASAN_DMA_DESC_NUM * 2 + 1) * 4, \ + GFP_KERNEL); + + if (unlikely(host->adma_desc == NULL)) + return -ENOMEM; + + return 0; +} + +static void arasan_adma_table_pre(struct arasan_host *host, + struct mmc_data *data) +{ + int direction, i; + u8 *desc; + struct scatterlist *sg; + int len; + dma_addr_t addr; + + if (host->status == STATE_DATA_READ) + direction = DMA_FROM_DEVICE; + else + direction = DMA_TO_DEVICE; + + DBG("\t%s: sg entries %d\n", __func__, data->sg_len); + + /* + * 得到scatterlist当中有多少个内在块需要传输 + * 实际上sg_frags在正常的情况下的值 = data->sg_len + * -这个函数的实际目的是将虚拟地址映射成物理地址 + * 这里和主调函数当中作的动作是一样的,所以这里可以屏蔽掉 + */ + /* + host->sg_frags = dma_map_sg(mmc_dev(host->mmc), data->sg, + data->sg_len, direction); + */ + desc = host->adma_desc; + + //printk("sg_frags:%d\n", host->sg_frags); + for_each_sg(data->sg, sg, host->sg_frags, i) { + addr = sg_dma_address(sg); /* 每一个scatter指定的DMA传输的地址 */ + len = sg_dma_len(sg); + //printk("len:%d\n", len); + //printk("addr:%x\n", addr); + + DBG("\t\tFrag %d: addr 0x%x, len %d\n", i, addr, len); + + /* Preparing the descriptor */ + desc[7] = (addr >> 24) & 0xff; + desc[6] = (addr >> 16) & 0xff; + desc[5] = (addr >> 8) & 0xff; + desc[4] = (addr >> 0) & 0xff; + + desc[3] = (len >> 8) & 0xff; + desc[2] = (len >> 0) & 0xff; + + desc[1] = 0x00; + desc[0] = 0x21; + + desc += 8; + } + //printk("i=%d\n", i); + /* 返回到最后一个descriptor,并将该descriptor设置为最后一个descriptor, + * 让sdio知道什么时候停止取descriptor + */ + desc -= 8; + desc[0] = 0x23; + + arasan_adma_dump_desc(host->adma_desc); + + /* 将kmalloc获得的descriptors的虚拟地址转换成物理地址 */ + host->adma_addr = dma_map_single(mmc_dev(host->mmc), + host->adma_desc, + (ARASAN_DMA_DESC_NUM * 2 + 1) * 4, + DMA_TO_DEVICE); + + writel(host->adma_addr, host->base + ARASAN_ADMA_ADDRESS); +} + +static void arasan_adma_table_post(struct arasan_host *host, + struct mmc_data *data) +{ + int direction; + + if (host->status == STATE_DATA_READ) + direction = DMA_FROM_DEVICE; + else + direction = DMA_TO_DEVICE; + + DBG("\t%s\n", __func__); + + dma_unmap_single(mmc_dev(host->mmc), host->adma_addr, + (ARASAN_DMA_DESC_NUM * 2 + 1) * 4, DMA_TO_DEVICE); + + dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, direction); +} + +static int arasan_setup_data(struct arasan_host *host) +{ + u16 blksz=0; + u16 xfer = 0; + struct mmc_data *data = host->mrq->data; + + DBG("%s:\n\t%s mode, data dir: %s; Buff=0x%08x," + "blocks=%d, blksz=%d\n", __func__, host->use_pio ? "PIO" : "DMA", + (data->flags & MMC_DATA_READ) ? "read" : "write", + (unsigned int)sg_virt(data->sg), data->blocks, data->blksz); + + /* Transfer Direction */ + if (data->flags & MMC_DATA_READ) { + xfer |= ARASAN_XFER_DATA_DIR; + host->status = STATE_DATA_READ; + } else { + xfer &= ~ARASAN_XFER_DATA_DIR; + host->status = STATE_DATA_WRITE; + } + + xfer |= ARASAN_XFER_BLK_COUNT_EN; + + if (data->blocks > 1) { + if (host->auto_cmd12) // sd2.0 + xfer |= ARASAN_XFER_MULTI_BLK | ARASAN_XFER_AUTOCMD12; + else // sdio2.0 + xfer |= ARASAN_XFER_MULTI_BLK; + } + + //printk("blksz:%d\n", data->blksz); + /* Set the block size register */ + //blksz = ARASAN_BLOCK_SIZE_SDMA_512KB; + blksz |= (data->blksz & ARASAN_BLOCK_SIZE_TRANSFER); + blksz |= (data->blksz & 0x1000) ? ARASAN_BLOCK_SIZE_SDMA_8KB : 0; + + //printk("blksz:%x\n", blksz); + writew(blksz, host->base + ARASAN_BLK_SIZE); + + /* Set the block count register */ + writew(data->blocks, host->base + ARASAN_BLK_COUNT); + //printk("blocks:%d\n", data->blocks); + + /* PIO mode is used when 'pio' var is set by the user or no + * sdma is available from HC caps. */ + if (unlikely(host->use_pio || (host->cap.sdma == 0))) { + int i = 0; + struct scatterlist *_sg; + //int len; + + _sg = NULL; + host->sg = NULL; + host->sg_frags = dma_map_sg(mmc_dev(host->mmc), data->sg, + data->sg_len, + (host->status & STATE_DATA_READ) ? + DMA_FROM_DEVICE : DMA_TO_DEVICE); + + host->sg = (struct scatterlist **)kmalloc(sizeof(struct scatterlist*)*host->sg_frags,GFP_KERNEL); + if (unlikely(host->sg==NULL)) { + printk("SD-MMC kmalloc failed.\n"); + return -ENOMEM; + } + + //printk("sg_frags:%d\n", host->sg_frags); + for_each_sg(data->sg, _sg, host->sg_frags, i) { + host->sg[i] = _sg; + //printk("sg_len:%d\n",sg_dma_len(_sg)); + } + + /* PIO的数据传输在中断当中完成 */ + //printk("blksz:%d\n", blksz); + //printk("blocks:%d\n", data->blocks); + host->pio_blksz = data->blksz; + host->pio_blocks = data->blocks; + //host->pio_blkbuf = sg_virt(data->sg); + } else { + dma_addr_t phys_addr; + + /* Enable DMA */ + xfer |= ARASAN_XFER_DMA_EN; + + /* Scatter list init */ + host->sg_frags = dma_map_sg(mmc_dev(host->mmc), data->sg, + data->sg_len, + (host->status & STATE_DATA_READ) ? + DMA_FROM_DEVICE : DMA_TO_DEVICE); + + phys_addr = sg_dma_address(data->sg); + + if (likely(host->adma)) { + /* Set the host control register dma bits for adma + * if supported and enabled by user. */ + host->ctrl |= ARASAN_HOST_CTRL_ADMA2_32; + + /* Prepare ADMA table */ + arasan_adma_table_pre(host, data); + } else { + /* SDMA Mode selected (default mode) */ + host->ctrl &= ~ARASAN_HOST_CTRL_ADMA2_64; + + writel((unsigned int)phys_addr, + host->base + ARASAN_SDMA_SYS_ADDR); + } + writeb(host->ctrl, host->base + ARASAN_HOST_CTRL); + + } + /* Set the data transfer mode register */ + writew(xfer, host->base + ARASAN_XFER_MODE); + + DBG("\tHC Reg [xfer 0x%x] [blksz 0x%x] [blkcount 0x%x] [CRTL 0x%x]\n", + readw(host->base + ARASAN_XFER_MODE), + readw(host->base + ARASAN_BLK_SIZE), + readw(host->base + ARASAN_BLK_COUNT), + readb(host->base + ARASAN_HOST_CTRL)); + + return 0; +} + +static void arasan_finish_data(struct arasan_host *host) +{ + struct mmc_data *data = host->mrq->data; + + DBG("\t%s\n", __func__); + + if (unlikely(host->pio_blkbuf)) { + host->pio_blksz = 0; + host->pio_blocks = 0; + host->pio_blkbuf = NULL; + } else { + if (likely(host->adma)) { + arasan_adma_table_post(host, data); + } else { + dma_unmap_sg(mmc_dev(host->mmc), data->sg, + host->sg_frags, + (host->status & STATE_DATA_READ) ? + DMA_FROM_DEVICE : DMA_TO_DEVICE); + } + } + + data->bytes_xfered = data->blocks * data->blksz; + host->status = STATE_CMD; +} + +static int arasan_finish_cmd(unsigned int err_status, unsigned int status, + unsigned int opcode) +{ + int ret = 0; + + if (unlikely(err_status)) { + if (err_status & ARASAN_CMD_TIMEOUT) { + //printk("sdio cmd_timeout...\n"); + ret = -ETIMEDOUT; + } + if (err_status & ARASAN_CMD_CRC_ERROR) { + printk("sdio cmd_crc_error...\n"); + ret = -EILSEQ; + } + if (err_status & ARASAN_CMD_END_BIT_ERROR) { + printk("sdio cmd_end_bit_error...\n"); + ret = -EILSEQ; + } + if (err_status & ARASAN_CMD_INDEX_ERROR) { + printk("sdio cmd_index_error...\n"); + ret = -EILSEQ; + } + } + if (likely(status & ARASAN_N_CMD_COMPLETE)) + DBG("\tCommand (CMD%u) Completed irq...\n", opcode); + + return ret; +} + +//#define ARASAN_IRQ_DEFAULT_MASK 0x02ff00fb +/* Enable/Disable Normal and Error interrupts */ +static void aranan_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + unsigned long flags; + struct arasan_host *host = mmc_priv(mmc); + static unsigned int arasan_irq_mask; + + DBG("%s: %s CARD_IRQ\n", __func__, enable ? "enable" : "disable"); + //printk("%s: %s CARD_IRQ\n", __func__, enable ? "enable" : "disable"); + + arasan_irq_mask = host->card_irq ?ARASAN_IRQ_DEFAULT_MASK: + ARASAN_IRQ_DEFAULT_MASK_NOCARDIRQ; + spin_lock_irqsave(&host->lock, flags); + if (enable) + host->intr_en = arasan_irq_mask; + else + host->intr_en = 0; + + writel(host->intr_en, host->base + ARASAN_NORMAL_INT_STATUS_EN); + writel(host->intr_en, host->base + ARASAN_NORMAL_INT_SIGN_EN); + spin_unlock_irqrestore(&host->lock, flags); +} + +static void arasan_timeout_timer(unsigned long data) +{ + struct arasan_host *host = (struct arasan_host *)data; + struct mmc_request *mrq; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + + //printk("timeout.\n"); + //printk("host->status:%d\n", host->status); + if ((host->mrq) && ((host->status==STATE_CMD) || + (host->status==STATE_DATA_READ) || + (host->status==STATE_DATA_WRITE))) { + mrq = host->mrq; + + DBG("%s: Timeout waiting for hardware interrupt.\n", + mmc_hostname(host->mmc)); + + writel(0xffffffff, host->base + ARASAN_NORMAL_INT_STATUS); + + + if (mrq->data) { + arasan_finish_data(host); + arsan_sw_reset(host, reset_dat_line); + mrq->data->error = -ETIMEDOUT; + } + if (likely(mrq->cmd)) { + mrq->cmd->error = -ETIMEDOUT; + arsan_sw_reset(host, reset_cmd_line); + arasan_get_resp(mrq->cmd, host); + } + arasan_ctrl_led(host, 0); + host->mrq = NULL; + mmc_request_done(host->mmc, mrq); + } + spin_unlock_irqrestore(&host->lock, flags); +} + +/* Process requests from the MMC layer */ +static void arasan_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + /* 进入到这个函数时,mrq当中有用的就只剩下cmd和data */ + struct arasan_host *host = mmc_priv(mmc); + struct mmc_command *cmd = mrq->cmd; + unsigned long flags; + + BUG_ON(host->mrq != NULL); + + + spin_lock_irqsave(&host->lock, flags); + + DBG(">>> araran_request:\n"); + /* Check that there is a card in the slot */ + if (unlikely(arasan_test_card(host) < 0)) { + DBG("%s: Error: No card present...\n", mmc_hostname(host->mmc)); + + mrq->cmd->error = -ENOMEDIUM; + mmc_request_done(mmc, mrq); /* 来自core.c,通知上层操作已经完成 */ + spin_unlock_irqrestore(&host->lock, flags); + return; + } + //printk(KERN_EMERG"The card is present.\n"); + + host->mrq = mrq; + + host->status = STATE_CMD; + if (likely(mrq->data)) { + //printk("1\n"); + //mdelay(10000); + arasan_setup_data(host); + } + + + /* Turn-on/off the LED when send/complete a cmd */ + arasan_ctrl_led(host, 1); + + //printk("start_cmd.\n"); + //mdelay(5000); + arasan_start_cmd(host, cmd); + + mod_timer(&host->timer, jiffies + 5 * HZ); + + + DBG("<<< araran_request done!\n"); + //printk("<<< araran_request done!\n"); + spin_unlock_irqrestore(&host->lock, flags); +} + +static int arasan_get_ro(struct mmc_host *mmc) +{ + struct arasan_host *host = mmc_priv(mmc); + + u32 ro = readl(host->base + ARASAN_PRESENT_STATE); + if (!(ro & ARASAN_PRESENT_STATE_WR_EN)) + return 1; + + return 0; +} + +/* I/O bus settings (MMC clock/power ...) */ +static void arasan_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct arasan_host *host = mmc_priv(mmc); + u8 ctrl_reg = readb(host->base + ARASAN_HOST_CTRL); + + DBG("%s: pwr %d, clk %d, vdd %d, bus_width %d, timing %d\n", + __func__, ios->power_mode, ios->clock, ios->vdd, ios->bus_width, + ios->timing); + //printk(KERN_EMERG"clk:%d\n", ios->clock); + + /* Set the power supply mode */ + if (ios->power_mode == MMC_POWER_OFF) { + arasan_power_set(host, 0, ios->vdd); + } + else { + //printk("powerup.\n"); + //mdelay(5000); + arasan_power_set(host, 1, ios->vdd); + //printk("after powerup.\n"); + //mdelay(5000); + } + + /* Timing (high speed supported?) */ + if ((ios->timing == MMC_TIMING_MMC_HS || + ios->timing == MMC_TIMING_SD_HS) && host->cap.high_speed) + /* + * 本调试板在高速模式下同样只能用下降沿输出 + */ + { + //ctrl_reg |= ARASAN_HOST_CTRL_HIGH_SPEED; + } + ctrl_reg |= ARASAN_HOST_CTRL_HIGH_SPEED; + /* Clear the current bus width configuration */ + ctrl_reg &= ~ARASAN_HOST_CTRL_SD_MASK; + + /* Set SD bus bit mode */ + switch (ios->bus_width) { + case MMC_BUS_WIDTH_8: + ctrl_reg |= ARASAN_HOST_CTRL_SD8; + break; + case MMC_BUS_WIDTH_4: + ctrl_reg |= ARASAN_HOST_CTRL_SD; + break; + /* added by me, 不能插拔识别卡的问题 */ + case MMC_BUS_WIDTH_1: + ctrl_reg &= ~ARASAN_HOST_CTRL_SD; + break; + } + + /* Default to maximum timeout */ + writeb(0x0e, host->base + ARASAN_TIMEOUT_CTRL); + + /* Disable Card Interrupt in Host in case we change + * the Bus Width. */ + aranan_enable_sdio_irq(host->mmc, 0); + + host->ctrl = ctrl_reg; + writeb(host->ctrl, host->base + ARASAN_HOST_CTRL); + + aranan_enable_sdio_irq(host->mmc, 1); + + /* Set clock */ + arasan_set_clock(host, ios->clock); + //printk(KERN_EMERG"clk set done.\n"); + //mdelay(5000); +} + +/* Tasklet for Card-detection */ +static void arasan_tasklet_card(unsigned long data) +{ + unsigned long flags; + struct arasan_host *host = (struct arasan_host *)data; + + spin_lock_irqsave(&host->lock, flags); + + if (likely((readl(host->base + ARASAN_PRESENT_STATE) & + ARASAN_PRESENT_STATE_CARD_PRESENT))) { + if (host->mrq) { + // printk("card_detection.\n"); + pr_err("%s: Card removed during transfer!\n", + mmc_hostname(host->mmc)); + /* Reset cmd and dat lines */ + arsan_sw_reset(host, reset_cmd_line); + arsan_sw_reset(host, reset_dat_line); + + if (likely(host->mrq->cmd)) { + struct mmc_request *mrq = host->mrq; + mrq->cmd->error = -ENOMEDIUM; + host->mrq = NULL; + mmc_request_done(host->mmc, mrq); + } + } + } + + spin_unlock_irqrestore(&host->lock, flags); + + if (likely(host->mmc)) + mmc_detect_change(host->mmc, msecs_to_jiffies(200)); +} + +static void arasan_setup_hc(struct arasan_host *host); +static irqreturn_t arasan_irq(int irq, void *dev) +{ + struct arasan_host *host = dev; + unsigned int status, err_status, handled = 0; + unsigned short int_en; + struct mmc_command *cmd = NULL; + struct mmc_data *data = NULL; + + /* host->lock已经有加锁机制,所以这个变量不用担心互斥的产生 */ + //static int get_card_irq = 0; + + spin_lock(&host->lock); + + /* Interrupt Status */ + status = readl(host->base + ARASAN_NORMAL_INT_STATUS); + err_status = (status >> 16) & 0xffff; + + /* 清中断状态寄存器 */ + DBG("\tclear status and exit...\n"); + writel(status, host->base + ARASAN_NORMAL_INT_STATUS); + + if (likely(status & ARASAN_N_CARD_IRQ)) { + /* 进入这个中断时不能直接退出,因为这个接收到这个中断 + * 时,还可能接收到数据完成中断 + */ + /* + * mmc_signal_sdio_irq(host->mmc); + * 这让人崩溃,这个函数里面将所有的中断关闭掉,在这期间是会有 + * 其它的中断的(这是由于实现不同造成的), 所以这里用下面的方法 + * 取代,只关闭sdio中断 + */ + int_en = readl(host->base+ARASAN_NORMAL_INT_STATUS_EN); + int_en &= ~(0x1<<8); + + writel(int_en, host->base + ARASAN_NORMAL_INT_STATUS_EN); + /* + * 替代 wake_up_prcess,因为我们对外设由电源开关,而在 + * 本分代码的逻辑上是先打开中断,然后在打开开关,这就造成 + * 在打开中断时,dat1为低,造成中断,但此时,sdio_irq_thread + * 还未被赋值 + */ + host->mmc->sdio_irq_pending = true; + if (host->mmc && host->mmc->sdio_irq_thread) + wake_up_process(host->mmc->sdio_irq_thread); + + } + +#if 0 + if ((status&ARASAN_N_CARD_REMOVAL) || + (status&ARASAN_N_CARD_INS)) { + /* 防止中断抖动 */ + int_en = readw(host->base + ARASAN_NORMAL_INT_SIGN_EN); + //printk("int_en:%x\n", int_en); + int_en = (int_en & (~(0x3<<6))); + //printk("int_en:%x\n", int_en); + writew(int_en, host->base+ARASAN_NORMAL_INT_SIGN_EN); + } +#endif + + + DBG("%s: Normal IRQ status 0x%x, Error status 0x%x\n", + __func__, status & 0xffff, err_status); + + //printk("z\n"); + /* + printk(KERN_EMERG"%s: Normal IRQ status 0x%x, Error status 0x%x\n", + __func__, status & 0xffff, err_status); + */ + //printk("arasan_irq.\n"); + // + + if ((!host->need_poll) && + ((status & ARASAN_N_CARD_INS) || + (status & ARASAN_N_CARD_REMOVAL))) { + tasklet_schedule(&host->card_tasklet); + } + + if (unlikely(!host->mrq)) { + goto out; + } + + + cmd = host->mrq->cmd; + data = host->mrq->data; + + cmd->error = 0; + /* Check for any CMD interrupts */ + if (likely(status & ARASAN_INT_CMD_MASK)) { + //printk("response to cmd.\n"); + cmd->error = arasan_finish_cmd(err_status, status, cmd->opcode); + if (cmd->error) + arsan_sw_reset(host, reset_cmd_line); + + if ((host->status == STATE_CMD) || cmd->error) { + arasan_get_resp(cmd, host); + + handled = 1; + } + } + + /* Check for any data interrupts */ + if (likely((status & ARASAN_INT_DATA_MASK)) && data) { + data->error = 0; + if (unlikely(err_status)) { + //printk("error.\n"); + if (err_status & ARASAN_DATA_TIMEOUT_ERROR) { + DBG("\tdata_timeout_error...\n"); + data->error = -ETIMEDOUT; + } + if (err_status & ARASAN_DATA_CRC_ERROR) { + DBG("\tdata_crc_error...\n"); + //printk("\tdata_crc_error...\n"); + data->error = -EILSEQ; + + } + if (err_status & ARASAN_DATA_END_ERROR) { + DBG("\tdata_end_error...\n"); + data->error = -EILSEQ; + } + if (err_status & ARASAN_AUTO_CMD12_ERROR) { + unsigned int err_cmd12 = + readw(host->base + ARASAN_CMD12_ERR_STATUS); + + DBG("\tc12err 0x%04x\n", err_cmd12); + + if (err_cmd12 & ARASAN_AUTOCMD12_ERR_NOTEXE) + data->stop->error = -ENOEXEC; + + if ((err_cmd12 & ARASAN_AUTOCMD12_ERR_TIMEOUT) + && !(err_cmd12 & ARASAN_AUTOCMD12_ERR_CRC)) + /* Timeout Error */ + data->stop->error = -ETIMEDOUT; + else if (!(err_cmd12 & + ARASAN_AUTOCMD12_ERR_TIMEOUT) + && (err_cmd12 & + ARASAN_AUTOCMD12_ERR_CRC)) + /* CRC Error */ + data->stop->error = -EILSEQ; + else if ((err_cmd12 & + ARASAN_AUTOCMD12_ERR_TIMEOUT) + && (err_cmd12 & + ARASAN_AUTOCMD12_ERR_CRC)) + DBG("\tCMD line Conflict\n"); + } + arsan_sw_reset(host, reset_dat_line); + handled = 1; + } else { + if (likely(((status & ARASAN_N_BUFF_READ) || + status & ARASAN_N_BUFF_WRITE))) { + DBG("\tData R/W interrupts...\n"); + //printk("\tData R/W interrupts...\n"); + arasan_data_pio(host); /* 使用pio的方式进行数据传输 + 必须在中断当中手动将数据 + 全部写入到buff当中去 + */ + } + + if (likely(status & ARASAN_N_DMA_IRQ)) + DBG("\tDMA interrupts...\n"); + + if (likely(status & ARASAN_N_TRANS_COMPLETE)) { + //printk("done.\n"); + DBG("\tData XFER completed interrupts...\n"); + arasan_finish_data(host); + if (data->stop) { + u32 opcode = data->stop->opcode; + data->stop->error = + arasan_finish_cmd(err_status, + status, opcode); + arasan_get_resp(data->stop, host); + } + handled = 1; + } + + } + } + if (err_status & ARASAN_ADMA_ERROR) { + //printk("3.\n"); + DBG("\tADMA Error...\n"); + arasan_adma_error(host); + cmd->error = -EIO; + } + if (err_status & ARASAN_CURRENT_LIMIT_ERROR) { + //printk("4.\n"); + DBG("\tPower Fail...\n"); + cmd->error = -EIO; + } + + if (likely(host->mrq && handled)) { + //printk("5.\n"); + struct mmc_request *mrq = host->mrq; + + arasan_ctrl_led(host, 0); + + del_timer(&host->timer); + + host->mrq = NULL; + //DBG("\tcalling mmc_request_done...\n"); + mmc_request_done(host->mmc, mrq); + } +out: + +#if 0 + if ((status&ARASAN_N_CARD_REMOVAL) || + (status&ARASAN_N_CARD_INS)) { + int_en = (int_en | (0x3<<6)); + //printk("int_en:%x\n", int_en); + writel(int_en, host->base + ARASAN_NORMAL_INT_STATUS_EN); + writew(int_en, host->base+ARASAN_NORMAL_INT_SIGN_EN); + } +#endif + + spin_unlock(&host->lock); + + return IRQ_HANDLED; +} + +static void arasan_setup_hc(struct arasan_host *host) +{ + /* Clear all the interrupts before resetting */ + arasan_clear_interrupts(host); + + /* Reset All and get the HC version */ + arsan_sw_reset(host, reset_all); + + /* Print HC version and SPEC */ + arsan_hc_version(host); + + /* Set capabilities and print theri info */ + arasan_capabilities(host); + + //printk("before arasan_set_interrupt.\n"); + //mdelay(10000); + + /* Enable interrupts */ + //arasan_set_interrupts(host); + + //printk("arasan_set_interrupt.\n"); + //mdelay(10000); +} + +static const struct mmc_host_ops arasan_ops = { + .request = arasan_request, + .get_ro = arasan_get_ro, /* 是否写保护 */ + .set_ios = arasan_set_ios, + .enable_sdio_irq = aranan_enable_sdio_irq, +}; + +static int arasan_probe(struct platform_device *pdev) +{ + struct mmc_host *mmc = NULL; + struct arasan_host *host = NULL; + const struct arasan_platform_data *arasan_data; + struct resource *r, *r1; + int ret, irq; + + + //printk(KERN_EMERG"platform_get_resource.\n"); + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + r1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + + //printk(KERN_EMERG"platform_get_irq_byname.\n"); + //irq = platform_get_irq_byname(pdev, "sdio1_irq"); + irq = r1->start; + + //printk(KERN_EMERG"irq:%d\n", irq); + //printk(KERN_EMERG"start:%x\n", r->start); + arasan_data = pdev->dev.platform_data; + + if (!r || irq < 0 || !arasan_data) + return -ENXIO; + + /* wifi pdn 引脚 */ + if (arasan_data->p_powerup != NULL) { + arasan_data->p_powerup(); + } else { + //printk("needn't powerup.\n"); + } + + + //printk(KERN_EMERG"request_mem_region.\n"); + r = request_mem_region(r->start, resource_size(r), pdev->name); + if (!r) { + pr_err("%s: ERROR: memory allocation failed\n", __func__); + return -EBUSY; + goto out; + } + //printk(KERN_EMERG"mmc_alloc_host.\n"); + /* Allocate the mmc_host with private data size */ + mmc = mmc_alloc_host(sizeof(struct arasan_host), &pdev->dev); + if (!mmc) { + pr_err("%s: ERROR: mmc_alloc_host failed\n", __func__); + ret = -ENOMEM; + goto out; + } + + /* Verify resource from the platform */ + //printk(KERN_EMERG"arasan_claim_host.\n"); + ret = arasan_claim_resource(pdev); + if (ret < 0) + goto out; + + host = mmc_priv(mmc); + host->mmc = mmc; + host->dev = &pdev->dev; + host->res = r; + + /* card_irq + * sd卡不接收card_irq + */ + host->card_irq = arasan_data->card_irq; + + /* auto_cmd12 + * 区别sdio2.0和sd2.0的多块传输 + * sdio2.0-cmd52 + */ + host->auto_cmd12 = arasan_data->auto_cmd12; + + /* use_pio + * 使用主机读取buf,还是DMA完成数据的传输 + */ + host->use_pio = arasan_data->use_pio; + //printk("host->use_pio=%d\n", host->use_pio); + + /* + * need_detect + * wifi和sd卡使用同一个驱动,sd卡需要进行探测,而wifi不需要 + * 这里影响每次发送请求时是否判断卡的存在 + */ + host->need_detect = arasan_data->need_detect; + //printk("host->need_detect=%d\n", host->need_detect); + + host->sdio_4bit_data = arasan_data->sdio_4bit_data; + + /* + * need_poll 表示是否由子系统来完成卡的探测 , + * 这里从表面上看起来其实是一样的,因为arasan_tasklet_card也是启动 + * host->detect工作队列 + */ + host->need_poll = arasan_data->need_poll; + if (host->need_poll) { + mmc->caps |= MMC_CAP_NEEDS_POLL; + DBG("\tHC needs polling to detect the card..."); + } else + /* no set the MMC_CAP_NEEDS_POLL in cap */ + tasklet_init(&host->card_tasklet, arasan_tasklet_card, + (unsigned long)host); + + //printk(KERN_EMERG"ioremap.\n"); + //printk(KERN_EMERG"r->start:%x\n", r->start); + host->base = ioremap(r->start, resource_size(r)); + if (!host->base) { + pr_err("%s: ERROR: memory mapping failed\n", __func__); + ret = -ENOMEM; + goto out; + } + //printk(KERN_EMERG"host->base:%x\n", host->base); + + //printk(KERN_EMERG"request_irq.\n"); + ret = + request_irq(irq, arasan_irq, IRQF_SHARED, ARASAN_DRIVER_NAME, host); + if (ret) { + pr_err("%s: cannot assign irq %d\n", __func__, irq); + goto out; + } else + host->irq = irq; + + spin_lock_init(&host->lock); + + /* Setup the Host Controller according to its capabilities */ + //printk(KERN_EMERG"arasan_setup_hc.\n"); + arasan_setup_hc(host); + + mmc->ops = &arasan_ops; + + /* 这些支持的电压值会被用做探测过程中协商host与sd卡的电压 */ + if (host->cap.voltage33) + mmc->ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34; + if (host->cap.voltage30) + mmc->ocr_avail |= MMC_VDD_29_30; + if (host->cap.voltage18) + mmc->ocr_avail |= MMC_VDD_165_195; + + mmc->caps = MMC_CAP_SDIO_IRQ; /* sdio 使用 */ + + /* + * 在探测时不使用spi模式 + */ +#if 0 + if (host->cap.spi) + mmc->caps |= MMC_CAP_SPI; +#endif + /* mmc子系统会根据这个值来确认是否设置host的4bits/8bits总线宽度 */ + if (host->sdio_4bit_data) { + mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; + } + + /* mmc子系统会根据这个值来确认是否设置host的高速模式 */ + if (!host->card_irq) { + if (host->cap.high_speed) + mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; + } + + /* 在子系统当中没神马用 */ + host->freq = host->cap.timer_freq * 1000000; + //host->use_pio = pio; + + /* 在子系统当中没多大用,只是填充一个字段,上层想要知道这个值时,能够有一种方法获取 */ + mmc->f_max = maxfreq; + mmc->f_min = mmc->f_max / 256; + + /* + * Maximum block size. This is specified in the capabilities register. + */ + mmc->max_blk_size = host->cap.max_blk_len; + /* 确认一次最多传送多少块 */ + mmc->max_blk_count = 65535; + + /* + * 1表示接口一次只能完成一段数据的传输,另外的值表示能够完成多次传输 + * 根据max_seq_size的定义和影响,可以看出max_segs*max_seg_size最大为max_seq_size + * 8*65536 = 524288, 那为什么这里的值,我却设置为16啦?因为不是每个segment都能达 + * 到65536,根据实验发现它们不是所有的bio segment都能顺利和合并成65536,而这是因为 + * 这些segment可能在物理上并不连续,所以要设置为大于8,在最坏情况下,每个页框都不能 + * 合并,那么这个值应该为 524288/4096 = 128 + * + * 另外这个值的设置也和一次request的最大长度有关,虽然没有得到确切的理论依据,但 + * 根据试验结果来看,如果这个值设置过小,request的最大长度就不能达到下面设置的max_req_size + * + * 这里对性能有性能有一定的提升,读可提升10%-%15,写也提升可达10%左右 + * + */ + mmc->max_segs = 128; + //mmc->max_segs = 1; + + /* 一个segment即一次单位DMA传输,即表示一次单位DMA传输能传输多少数据,通常这个值为65535 */ + mmc->max_seg_size = 65536; + + /* + * 和这个参数相关的参数包括:max_hw_sector, max_sectors + * max_hw_sector则来自于max_seg_size/512,max_sector来自于max_hw_sectors和 + * BLK_DEF_MAX_SECTORS(1024)中较小的一个. + * + * 对于上层而言,它关心的参数是max_sector,它代表在通用块层一次最大能完成多少传输,可以看出这个值最大 + * 最大为1024,所以这个值设置成大于1024*512以上的值没有意义,为了增大吞吐量,这个值设为最大1024*512 + */ + //mmc->max_req_size = mmc->max_blk_count*mmc->max_blk_size; + mmc->max_req_size = 524288; + + /* Passing the "pio" option, we force the driver to not + * use any DMA engines. */ + if (unlikely(host->use_pio)) { + adma = 0; + DBG("\tPIO mode\n"); + printk("\tPIO mode\n"); + } else { + if (likely(adma)) { + /* Turn-on the ADMA if supported by the HW + * or Fall back to SDMA in case of failures */ + DBG("\tADMA mode\n"); + //printk("\tADMA mode\n"); + //printk(KERN_EMERG"arasan_init_sg.\n"); + ret = arasan_init_sg(host); + if (unlikely(ret)) { + pr_warning("\tSG init failed (disable ADMA)\n"); + adma = 0; + } else { + /* Set the Maximum number of segments + * becasue we can do scatter/gathering in ADMA + * mode. */ + //mmc->max_hw_segs = 128; + } + } else + DBG("\tSDMA mode\n"); + } + host->adma = adma; + + //printk("before add host.\n"); + //mdelay(10000); + + platform_set_drvdata(pdev, mmc); + ret = mmc_add_host(mmc); + if (ret) + goto out; + + /* + * 定义一个定时器,超时时间在mod_timer当中定义 + * */ + //printk(KERN_EMERG"setup_timer.\n"); + setup_timer(&host->timer, arasan_timeout_timer, (unsigned long)host); + + pr_info("%s: driver initialized... IRQ: %d, Base addr 0x%x\n", + mmc_hostname(mmc), irq, (unsigned int)host->base); + +//#ifdef ARASAN_DEBUG + led = 1; +//#endif + return 0; +out: + if (host) { + if (host->irq) + free_irq(host->irq, host); + if (host->base) + iounmap(host->base); + } + if (r) + release_resource(r); + if (mmc) + mmc_free_host(mmc); + + return ret; +} + +static int arasan_remove(struct platform_device *pdev) +{ + struct mmc_host *mmc = platform_get_drvdata(pdev); + + if (mmc) { + struct arasan_host *host = mmc_priv(mmc); + + arasan_clear_interrupts(host); + free_irq(host->irq, host); + if (!host->need_poll) { + tasklet_kill(&host->card_tasklet); + } + mmc_remove_host(mmc); + arasan_power_set(host, 0, -1); + iounmap(host->base); + if (likely(host->adma)) + kfree(host->adma_desc); + release_resource(host->res); + mmc_free_host(mmc); + } + platform_set_drvdata(pdev, NULL); + return 0; +} + +static struct platform_driver arasan_driver = { + .probe = arasan_probe, + .remove = arasan_remove, + .driver = { + .name = ARASAN_DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + + +static int __init arasan_init(void) +{ + //printk(KERN_EMERG"arasan_init.\n"); + //platform_device_register(&arasan1_device); + //printk(KERN_EMERG"platform_river_register.\n"); + return platform_driver_register(&arasan_driver); +} + +static void __exit arasan_exit(void) +{ + //platform_device_unregister(&arasan1_device); + platform_driver_unregister(&arasan_driver); +} + +#if 0 +static int __init arasan_cmdline_opt(char *str) +{ + char *opt; + + if (!str || !*str) + return -EINVAL; + + while ((opt = strsep(&str, ",")) != NULL) { + if (!strncmp(opt, "maxfreq:", 8)) + strict_strtoul(opt + 8, 0, (unsigned long *)&maxfreq); + else if (!strncmp(opt, "adma:", 5)) + strict_strtoul(opt + 5, 0, (unsigned long *)&adma); + else if (!strncmp(opt, "led:", 4)) + strict_strtoul(opt + 4, 0, (unsigned long *)&led); + else if (!strncmp(opt, "pio:", 4)) + strict_strtoul(opt + 4, 0, (unsigned long *)&pio); + } + return 0; +} + +__setup("arasanmmc=", arasan_cmdline_opt); +#endif + +module_init(arasan_init); +module_exit(arasan_exit); + +MODULE_AUTHOR("Giuseppe Cavallaro "); +MODULE_DESCRIPTION("Arasan MMC/SD/SDIO Host Controller driver"); +MODULE_LICENSE("GPL"); diff -uarN a/drivers/mmc/host/arasan.h b/drivers/mmc/host/arasan.h --- a/drivers/mmc/host/arasan.h 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/mmc/host/arasan.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,239 @@ +/* + * Author: Giuseppe Cavallaro + * + * copyright (c) 2010 stmicroelectronics ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ARASAN_H +#define __ARASAN_H + +//#define ARASAN_CLOCKRATE_MAX 25000000 +#define ARASAN_CLOCKRATE_MAX 50000000 +#define ARASAN_DRIVER_NAME "arasan" +#define ARASAN_DMA_DESC_NUM 128 + +/* + * Register offsets + */ +#define ARASAN_SDMA_SYS_ADDR 0x000 +#define ARASAN_BLK_SIZE 0x004 +#define ARASAN_BLK_COUNT 0x006 +#define ARASAN_ARG 0x008 +#define ARASAN_XFER_MODE 0x00c +#define ARASAN_CMD 0x00e +#define ARASAN_RSP(i) (0x010 + ((i)<<2)) +#define ARASAN_RSP0 0x010 +#define ARASAN_RSP1 0x012 +#define ARASAN_RSP2 0x014 +#define ARASAN_RSP3 0x016 +#define ARASAN_RSP4 0x018 +#define ARASAN_RSP5 0x01a +#define ARASAN_RSP6 0x01c +#define ARASAN_RSP7 0x01e +#define ARASAN_BUFF 0x020 +#define ARASAN_PRESENT_STATE 0x024 +#define ARASAN_HOST_CTRL 0x028 +#define ARASAN_PWR_CTRL 0x029 +#define ARASAN_GAP_CTRL 0x02a +#define ARASAN_GAP_WAKEUP 0x02b +#define ARASAN_CLOCK_CTRL 0x02c +#define ARASAN_TIMEOUT_CTRL 0x02e +#define ARASAN_SW_RESET 0x02f + +#define ARASAN_NORMAL_INT_STATUS 0x030 +#define ARASAN_ERR_INT_STATUS 0x032 +#define ARASAN_NORMAL_INT_STATUS_EN 0x034 +#define ARASAN_ERR_INT_STATUS_EN 0x036 +#define ARASAN_NORMAL_INT_SIGN_EN 0x038 +#define ARASAN_ERR_INT_SIGN_EN 0x03a + +#define ARASAN_CMD12_ERR_STATUS 0x03c + +#define ARASAN_CAPABILITIES 0x040 + +#define ARASAN_ADMA_ERR_STATUS 0x054 +#define ARASAN_ADMA_ADDRESS 0x058 + +#define ARASAN_SPI_INT_SUPPORT 0x0f0 +#define ARASAN_HOST_VERSION 0x0fe + +/* Error Interrupt Status Register */ +#define ARASAN_CMD_TIMEOUT (1 << 0) +#define ARASAN_CMD_CRC_ERROR (1 << 1) +#define ARASAN_CMD_END_BIT_ERROR (1 << 2) +#define ARASAN_CMD_INDEX_ERROR (1 << 3) +#define ARASAN_DATA_TIMEOUT_ERROR (1 << 4) +#define ARASAN_DATA_CRC_ERROR (1 << 5) +#define ARASAN_DATA_END_ERROR (1 << 6) +#define ARASAN_CURRENT_LIMIT_ERROR (1 << 7) +#define ARASAN_AUTO_CMD12_ERROR (1 << 8) +#define ARASAN_ADMA_ERROR (1 << 9) +#define ARASAN_TARGET_RESP_ERROR (1 << 12) +#define ARASAN_CEATA_ERROR (1 << 13) + +/* Error Interrupt Status ENABLE reg. (0- Masked, 1: Enabled) */ +#define ARASAN_E_EN_CMD_TIMEOUT (1 << 0) +#define ARASAN_E_EN_CMD_CRC_ERROR (1 << 1) +#define ARASAN_E_EN_CMD_END_BIT_ERROR (1 << 2) +#define ARASAN_E_EN_CMD_INDEX_ERROR (1 << 3) +#define ARASAN_E_EN_DATA_TIMEOUT_ERROR (1 << 4) +#define ARASAN_E_EN_DATA_CRC_ERROR (1 << 5) +#define ARASAN_E_EN_DATA_END_ERROR (1 << 6) +#define ARASAN_E_EN_CURRENT_LIMIT_ERROR (1 << 7) +#define ARASAN_E_EN_AUTO_CMD12_ERROR (1 << 8) +#define ARASAN_E_EN_ADMA_ERROR (1 << 9) +#define ARASAN_E_EN_TARGET_RESP_ERROR (1 << 12) +#define ARASAN_E_EN_CEATA_ERROR (1 << 13) + +/* Normal Interrupt Status Register */ +#define ARASAN_N_CMD_COMPLETE (1 << 0) +#define ARASAN_N_TRANS_COMPLETE (1 << 1) +#define ARASAN_N_BLK_GAP_EVENT (1 << 2) +#define ARASAN_N_DMA_IRQ (1 << 3) +#define ARASAN_N_BUFF_WRITE (1 << 4) +#define ARASAN_N_BUFF_READ (1 << 5) +#define ARASAN_N_CARD_INS (1 << 6) +#define ARASAN_N_CARD_REMOVAL (1 << 7) +#define ARASAN_N_CARD_IRQ (1 << 8) +#define ARASAN_N_ERROR_IRQ (1 << 15) + +/* Normal Interrupt Status ENABLE reg. (0- Masked, 1: Enabled) */ +#define ARASAN_N_EN_CMD_COMPLETE (1 << 0) +#define ARASAN_N_EN_TRANS_COMPL (1 << 1) +#define ARASAN_N_EN_BLOCK_GAP (1 << 2) +#define ARASAN_N_EN_DMA_IRQ (1 << 3) +#define ARASAN_N_EN_BUFF_WRITE (1 << 4) +#define ARASAN_N_EN_BUFF_READ (1 << 5) +#define ARASAN_N_EN_CARD_INS (1 << 6) +#define ARASAN_N_EN_CARD_REM (1 << 7) +#define ARASAN_N_EN_CARD_IRQ (1 << 8) + +/* Default Enable Normal/Error interrupt mask */ +#define ARASAN_IRQ_DEFAULT_MASK 0x02ff01fb +#define ARASAN_IRQ_DEFAULT_MASK_NOCARDIRQ 0x02ff00fb + +/* Mask normal and error fields */ +#define ARASAN_INT_DATA_MASK 0x0070003a +#define ARASAN_INT_CMD_MASK 0x000f0001 + +/* Command Register */ +#define ARASAN_CMD_RSP_NONE (0 << 0) +#define ARASAN_CMD_RSP_136 (1 << 0) +#define ARASAN_CMD_RSP_48 (2 << 0) +#define ARASAN_CMD_RSP_48BUSY (3 << 0) +#define ARASAN_CMD_CHECK_CMDCRC (1 << 3) +#define ARASAN_CMD_INDX_CHECK (1 << 4) +#define ARASAN_CMD_DATA_PRESENT (1 << 5) +#define ARASAN_COMMAD_TYPE_NORM (0 << 6) +#define ARASAN_COMMAD_TYPE_SUSP (1 << 6) +#define ARASAN_COMMAD_TYPE_RESU (2 << 6) +#define ARASAN_COMMAD_TYPE_ABOR (3 << 6) +#define ARASAN_CMD_INDEX(x) ((x) << 8) + +/* Transfer Mode Register */ +#define ARASAN_XFER_DMA_EN (1 << 0) +#define ARASAN_XFER_BLK_COUNT_EN (1 << 1) +#define ARASAN_XFER_AUTOCMD12 (1 << 2) /* 1: Enable */ +#define ARASAN_XFER_DATA_DIR (1 << 4) /* 0: Write, 1: Read */ +#define ARASAN_XFER_MULTI_BLK (1 << 5) /* 0: Single 1: Multi */ +#define ARASAN_XFER_SPI_MODE (1 << 7) /* 1: SPI 0: SD Mode */ + +enum xfer_dat_cmd_status { +STATE_CMD = 0, +STATE_DATA_WRITE = 1, +STATE_DATA_READ = 2, +STATE_DATA_STOP = 3, +}; + +/* Software Reset */ +#define ARSAN_RESET_ALL 0x1 +#define ARSAN_RESET_CMD_LINE 0x2 +#define ARSAN_RESET_DAT_LINE 0x4 + +enum sw_reset_cmd { + reset_all = 0, + reset_cmd_line = 1, + reset_dat_line = 2, +}; + +/* Host Control Register */ +#define ARASAN_HOST_CTRL_LED (1 << 0) +#define ARASAN_HOST_CTRL_SD (1 << 1) /* 1: 4 bit mode */ +#define ARASAN_HOST_CTRL_HIGH_SPEED (1 << 2) +#define ARASAN_HOST_CTRL_SDMA_SEL (0 << 3) +#define ARASAN_HOST_CTRL_ADMA1 (1 << 3) +#define ARASAN_HOST_CTRL_ADMA2_32 (2 << 3) +#define ARASAN_HOST_CTRL_ADMA2_64 (3 << 3) +#define ARASAN_HOST_CTRL_SD8 (1 << 5) +#define ARASAN_HOST_CTRL_CARD_LEV_TEST (1 << 6) +#define ARASAN_HOST_CTRL_CARD_SIG_TEST (1 << 7) + +#define ARASAN_HOST_CTRL_SD_MASK 0x22 + +/* Clock Control Register */ +#define ARASAN_CLOCK_CTRL_SDCLK_MASK 0xff00 +#define ARASAN_CLOCK_CTRL_SDCLK_SHIFT 7 +#define ARASAN_CLOCK_CTRL_SDCLK_256 0x8000 +#define ARASAN_CLOCK_CTRL_SDCLK_128 0x4000 +#define ARASAN_CLOCK_CTRL_SDCLK_64 0x2000 +#define ARASAN_CLOCK_CTRL_SDCLK_32 0x1000 +#define ARASAN_CLOCK_CTRL_SDCLK_16 0x0800 +#define ARASAN_CLOCK_CTRL_SDCLK_8 0x0400 +#define ARASAN_CLOCK_CTRL_SDCLK_4 0x0200 +#define ARASAN_CLOCK_CTRL_SDCLK_2 0x0100 +#define ARASAN_CLOCK_CTRL_SDCLK_1 0x0000 +#define ARASAN_CLOCK_CTRL_SDCLK_ENABLE (1 << 2) +#define ARASAN_CLOCK_CTRL_ICLK_STABLE (1 << 1) +#define ARASAN_CLOCK_CTRL_ICLK_ENABLE (1 << 0) + +/* Power Control Register */ +#define ARASAN_PWR_CTRL_UP (1 << 0) /* 1: Power-On */ +#define ARASAN_PWR_BUS_VOLTAGE_33 (7 << 1) +#define ARASAN_PWR_BUS_VOLTAGE_30 (6 << 1) +#define ARASAN_PWR_BUS_VOLTAGE_18 (5 << 1) + +/* CMD12 error status bits */ +#define ARASAN_AUTOCMD12_ERR_NOTEXE (1 << 0) +#define ARASAN_AUTOCMD12_ERR_TIMEOUT (1 << 1) +#define ARASAN_AUTOCMD12_ERR_CRC (1 << 2) +#define ARASAN_AUTOCMD12_ERR_ENDBIT (1 << 3) +#define ARASAN_AUTOCMD12_ERR_INDEX (1 << 4) +#define ARASAN_AUTOCMD12_ERR_NOT_ISSUED (1 << 7) + +/* Present State Register */ +#define ARASAN_PRESENT_STATE_DAT7_4 0x1e000000 +#define ARASAN_PRESENT_STATE_CMD_LINE 0x01000000 +#define ARASAN_PRESENT_STATE_DAT3_0 0x00f00000 +#define ARASAN_PRESENT_STATE_WR_EN 0x00080000 +#define ARASAN_PRESENT_STATE_CARD_DETECT 0x00040000 +#define ARASAN_PRESENT_STATE_CARD_STABLE 0x00020000 +#define ARASAN_PRESENT_STATE_CARD_PRESENT 0x00010000 +#define ARASAN_PRESENT_STATE_BUFFER_RD_EN 0x00000800 +#define ARASAN_PRESENT_STATE_BUFFER_WR_EN 0x00000400 +#define ARASAN_PRESENT_STATE_RD_ACTIVE 0x00000200 +#define ARASAN_PRESENT_STATE_WR_ACTIVE 0x00000100 +#define ARASAN_PRESENT_STATE_DAT_ACTIVE 0x00000004 +#define ARASAN_PRESENT_STATE_DAT_INHIBIT 0x00000002 +#define ARASAN_PRESENT_STATE_CMD_INHIBIT 0x00000001 + +/* Block size register defines */ +#define ARASAN_BLOCK_SIZE_SDMA_512KB 0x7000 +#define ARASAN_BLOCK_SIZE_SDMA_256KB 0x6000 +#define ARASAN_BLOCK_SIZE_SDMA_128KB 0x5000 +#define ARASAN_BLOCK_SIZE_SDMA_64KB 0x4000 +#define ARASAN_BLOCK_SIZE_SDMA_32KB 0x3000 +#define ARASAN_BLOCK_SIZE_SDMA_16KB 0x2000 +#define ARASAN_BLOCK_SIZE_SDMA_8KB 0x1000 +#define ARASAN_BLOCK_SIZE_SDMA_4KB 0x0000 +#define ARASAN_BLOCK_SIZE_TRANSFER 0x0fff + +/* ADMA Error Status Register */ +#define ARASAN_ADMA_ERROR_LENGTH 0x04 +#define ARASAN_ADMA_ERROR_ST_TFR 0x03 +#define ARASAN_ADMA_ERROR_ST_FDS 0x01 +#define ARASAN_ADMA_ERROR_ST_STOP 0x00 +#endif diff -uarN a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c --- a/drivers/mmc/host/dw_mmc.c 2016-08-28 13:19:20.000000000 +0300 +++ b/drivers/mmc/host/dw_mmc.c 2018-11-21 06:44:38.000000000 +0300 @@ -285,7 +285,7 @@ mci_writel(host, CMDARG, cmd->arg); wmb(); - mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); + mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START | 1 << 29); } static void send_stop_cmd(struct dw_mci *host, struct mmc_data *data) @@ -611,7 +611,7 @@ mci_writel(host, CMDARG, arg); wmb(); - mci_writel(host, CMD, SDMMC_CMD_START | cmd); + mci_writel(host, CMD, SDMMC_CMD_START | cmd | 1 << 29); while (time_before(jiffies, timeout)) { cmd_status = mci_readl(host, CMD); @@ -639,6 +639,7 @@ div += 1; div = (host->bus_hz != slot->clock) ? DIV_ROUND_UP(div, 2) : 0; + dev_info(&slot->mmc->class_dev, "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ" @@ -799,6 +800,10 @@ else regs &= ~((0x1 << slot->id) << 16); + if (ios->timing == MMC_TIMING_MMC_HS200) { + mci_writel(slot->host, UHS_REG_EXT, 0x1000000); + } + mci_writel(slot->host, UHS_REG, regs); if (ios->clock) { @@ -1917,7 +1922,8 @@ if (host->pdata->get_ocr) mmc->ocr_avail = host->pdata->get_ocr(id); else - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + //mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + mmc->ocr_avail = MMC_VDD_165_195; /* * Start with slot power disabled, it will be enabled when a card @@ -2298,7 +2304,8 @@ fifo_size = host->pdata->fifo_depth; } host->fifo_depth = fifo_size; - host->fifoth_val = ((0x2 << 28) | ((fifo_size/2 - 1) << 16) | + //host->fifoth_val = ((0x2 << 28) | ((fifo_size/2 - 1) << 16) | + host->fifoth_val = ((0x2 << 28) | ((fifo_size/8/2 - 1) << 16) | ((fifo_size/2) << 0)); mci_writel(host, FIFOTH, host->fifoth_val); diff -uarN a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h --- a/drivers/mmc/host/dw_mmc.h 2016-08-28 13:19:20.000000000 +0300 +++ b/drivers/mmc/host/dw_mmc.h 2018-11-21 06:44:38.000000000 +0300 @@ -53,6 +53,7 @@ #define SDMMC_IDINTEN 0x090 #define SDMMC_DSCADDR 0x094 #define SDMMC_BUFADDR 0x098 +#define SDMMC_UHS_REG_EXT 0x108 #define SDMMC_DATA(x) (x) /* diff -uarN a/drivers/mmc/host/dw_mmc_xm_device.c b/drivers/mmc/host/dw_mmc_xm_device.c --- a/drivers/mmc/host/dw_mmc_xm_device.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/mmc/host/dw_mmc_xm_device.c 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dw_mmc.h" + +#if 0 +#define DW_MCI_CAPABILITIES (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED |\ + MMC_CAP_SD_HIGHSPEED | MMC_CAP_8_BIT_DATA |\ + MMC_CAP_SDIO_IRQ) +#endif + +#define DW_MCI_CAPABILITIES (MMC_CAP_MMC_HIGHSPEED | MMC_CAP_8_BIT_DATA) +#define DW_MCI_CAPABILITIES2 (MMC_CAP2_HS200_1_8V_SDR) + + +static struct resource dw_mci_resources[] = { + [0] = { + .start = EMMC_BASE, + .end = EMMC_BASE + 0xffff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = EMMC_IRQ, + .end = EMMC_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct dw_mci_board dw_board_data = { + .num_slots = 1, + .caps = DW_MCI_CAPABILITIES, + .caps2 = DW_MCI_CAPABILITIES2, + .bus_hz = 40 * 1000 * 1000, + .detect_delay_ms = 200, + //.fifo_depth = 512, +}; + +static struct platform_device dw_mci_device = +{ + .name = "dw_mmc", + .id = 0, + .num_resources = ARRAY_SIZE(dw_mci_resources), + .resource = dw_mci_resources, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &dw_board_data, + }, +}; + +static int __init dw_mci_driver_init(void) +{ + platform_device_register(&dw_mci_device); + return 0; +} + +static void __exit dw_mci_driver_exit(void) +{ + platform_device_unregister(&dw_mci_device); +} + +MODULE_LICENSE("GPL"); + +module_init(dw_mci_driver_init); +module_exit(dw_mci_driver_exit); + + + diff -uarN a/drivers/mmc/host/sdio0_sd.c b/drivers/mmc/host/sdio0_sd.c --- a/drivers/mmc/host/sdio0_sd.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/mmc/host/sdio0_sd.c 2019-02-14 05:41:45.000000000 +0300 @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include "arasan.h" + +static int detect = 0; +static int sdiocur = 0; +module_param(detect,int,S_IRUSR); +module_param(sdiocur ,int,S_IRUSR); + +static void arasan_release(struct device *device) +{ + return; +} + +static struct resource arasan0_resource[] = { + [0] = { + .name = "sdio0_addr", + .start = SDIO0_BASE, + .end = SDIO0_BASE + 0x100000 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "sdio0_irq", + .start = SDIO0_IRQ, + .end = SDIO0_IRQ, + .flags = IORESOURCE_IRQ, + } +}; + +void sdio0_powerup(void) +{ + int cur_bit = 0 << 6; + switch(sdiocur) + { + case 2:cur_bit = 0 << 6;break; + case 4:cur_bit = 1 << 6;break; + case 8:cur_bit = 2 << 6;break; + case 12:cur_bit = 3 << 6;break; + default :cur_bit = 0 << 6;break; + } + gpio_write(GPIO_MUX1_EN | cur_bit, 43); //sdio0_clk + gpio_write(GPIO_MUX1_EN | cur_bit, 44); //sdio0_cmd + gpio_write(GPIO_MUX1_EN | cur_bit, 45); //sdio0_data0 + gpio_write(GPIO_MUX1_EN | cur_bit, 46); //sdio0_data1 + gpio_write(GPIO_MUX1_EN | cur_bit, 47); //sdio0_data2 + gpio_write(GPIO_MUX1_EN | cur_bit, 48); //sdio0_data3 + writel(0x80,IOMEM(IO_ADDRESS(0x100203e0))); + + if(detect) { + gpio_write(GPIO_MUX1_EN | GPIO_DRIVE_8MA, 49); //sdio0_detect + gpio_write(GPIO_MUX1_EN | GPIO_DRIVE_8MA, 50); //sdio0_pwsv + } else { + gpio_write(GPIO_DRIVE_8MA, 49); + gpio_write(GPIO_OUT_EN | GPIO_OUT_LOW, 50); + } + + gpio_write(GPIO_DRIVE_8MA, 51); //sdio0_writeprotect + gpio_write(GPIO_MUX1_EN | GPIO_DRIVE_8MA, 52); //sdio0_lenon +} + +struct arasan_platform_data arasan0_platform_data = { + .need_poll = 0, + .need_detect = 0, + .use_pio = 0, + .auto_cmd12 = 1, + .card_irq = 0, + .sdio_4bit_data = 1, + .p_powerup = sdio0_powerup, +}; + +/* sdio 0 */ +static struct platform_device arasan0_device = { + .id = 0, + .name = ARASAN_DRIVER_NAME, + .num_resources = ARRAY_SIZE(arasan0_resource), + .resource = arasan0_resource, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &arasan0_platform_data, + .release = arasan_release, + } +}; + +static int __init arasan0_init(void) +{ + if(detect) + { + arasan0_platform_data.need_detect = 1; + } + platform_device_register(&arasan0_device); + + return 0; +} + +static void __exit arasan0_exit(void) +{ + platform_device_unregister(&arasan0_device); +} + +module_init(arasan0_init); +module_exit(arasan0_exit); + +MODULE_LICENSE("GPL"); + diff -uarN a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig --- a/drivers/mtd/devices/Kconfig 2016-08-28 13:19:20.000000000 +0300 +++ b/drivers/mtd/devices/Kconfig 2018-11-21 06:44:38.000000000 +0300 @@ -279,4 +279,6 @@ LinuxBIOS or if you need to recover a DiskOnChip Millennium on which you have managed to wipe the first block. +source "drivers/mtd/devices/xmsfc/Kconfig" + endmenu diff -uarN a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile --- a/drivers/mtd/devices/Makefile 2016-08-28 13:19:20.000000000 +0300 +++ b/drivers/mtd/devices/Makefile 2018-11-21 06:44:38.000000000 +0300 @@ -17,5 +17,6 @@ obj-$(CONFIG_MTD_SST25L) += sst25l.o obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o +obj-y += xmsfc/ CFLAGS_docg3.o += -I$(src) diff -uarN a/drivers/mtd/devices/xmsfc/Kconfig b/drivers/mtd/devices/xmsfc/Kconfig --- a/drivers/mtd/devices/xmsfc/Kconfig 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/mtd/devices/xmsfc/Kconfig 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,8 @@ +config MTD_XMSFC + tristate "xm spi flash controller device driver" + depends on ARCH_XM530 || ARCH_XM580 + default y if ARCH_XM530 || ARCH_XM580 + help + xm spi flash controller device driver + + diff -uarN a/drivers/mtd/devices/xmsfc/Makefile b/drivers/mtd/devices/xmsfc/Makefile --- a/drivers/mtd/devices/xmsfc/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/mtd/devices/xmsfc/Makefile 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,3 @@ +obj-$(CONFIG_MTD_XMSFC) += xmsfc_v2.o xmsfc_params.o + + diff -uarN a/drivers/mtd/devices/xmsfc/xmsfc.c b/drivers/mtd/devices/xmsfc/xmsfc.c --- a/drivers/mtd/devices/xmsfc/xmsfc.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/mtd/devices/xmsfc/xmsfc.c 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,372 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../mtdcore.h" + +#include "xmsfc.h" + +extern const struct xmsfc_params xmsfc_params_table[]; +extern const struct xmsfc_params xmsfc_params_default; + +static int xmsfc_reg_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + unsigned long long offset = instr->addr; + unsigned long long length = instr->len; + unsigned int timeout = 0x10000000; + struct xmsfc_host *host = MTD_TO_HOST(mtd); + + if (offset + length > mtd->size) { + DBG_MSG("erase area out of range of mtd.\n"); + return -EINVAL; + } + + if ((unsigned int)offset & (mtd->erasesize-1)) { + DBG_MSG("erase start address is not alignment.\n"); + return -EINVAL; + } + // + if ((unsigned int)length & (mtd->erasesize-1)) { + DBG_MSG("erase length is not alignment.\n"); + return -EINVAL; + } + + mutex_lock(&host->lock); + while (length) + { + writel(offset, XMSFC_REG_ADDR); + writel(host->cmd_erase, XMSFC_REG_CMD); + writel(XMSFC_OP2, XMSFC_REG_OP); + + while((readl(XMSFC_REG_ST) & XMSFC_OP2_OK) == 0) + { + if(--timeout == 0) + { + instr->state = MTD_ERASE_FAILED; + mutex_unlock(&host->lock); + return -EIO; + } + } + + //this command for MPW + writel(0x05,XMSFC_REG_CMD); + writel(XMSFC_OP3, XMSFC_REG_OP); + while((readl(XMSFC_REG_ST) & XMSFC_OP3_OK) == 0) + { + if(--timeout == 0) + { + instr->state = MTD_ERASE_FAILED; + mutex_unlock(&host->lock); + return -EIO; + } + } + + offset += mtd->erasesize; + length -= mtd->erasesize; + } + instr->state = MTD_ERASE_DONE; + mutex_unlock(&host->lock); + mtd_erase_callback(instr); + + return 0; +} + +static int xmsfc_reg_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct xmsfc_host *host = MTD_TO_HOST(mtd); + unsigned char *ptr = (unsigned char *)buf; + int num = 0; + int index = 0; + int remain = 0; + + if ((to + len) > mtd->size) { + DBG_MSG("write data out of range.\n"); + return -EINVAL; + } + + *retlen = 0; + if (!len) { + DBG_MSG("write length is 0.\n"); + return 0; + } + mutex_lock(&host->lock); + + while(len > 0) + { + remain = (to % XMSFC_REG_BUF_SIZE); + num = ((len >= XMSFC_REG_BUF_SIZE - remain) ? XMSFC_REG_BUF_SIZE - remain : len); + + writel(to, XMSFC_REG_ADDR); + writel(num - 1, XMSFC_REG_WRNUM); + + index = 0; + while(index < num) + { + writel(*(ptr + index), XMSFC_REG_BUF + 4 * index); + index++; + } + writel(host->cmd_write, XMSFC_REG_CMD); + writel(XMSFC_OP6, XMSFC_REG_OP); + while((readl(XMSFC_REG_ST) & XMSFC_OP6_OK) == 0); + + //this command for MPW + writel(0x05,XMSFC_REG_CMD); + writel(XMSFC_OP3, XMSFC_REG_OP); + while((readl(XMSFC_REG_ST) & XMSFC_OP3_OK) == 0); + + to += num; + ptr += num; + len -= num; + } + *retlen = (size_t)(ptr - buf); + + mutex_unlock(&host->lock); + return 0; +} +static int xmsfc_bus_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + int num; + int result = -EIO; + unsigned char *ptr = buf; + struct xmsfc_host *host = MTD_TO_HOST(mtd); + + if ((from + len) > mtd->size) { + DBG_MSG("read area out of range.\n"); + return -EINVAL; + } + + *retlen = 0; + if (!len) { + DBG_MSG("read length is 0.\n"); + return 0; + } + + mutex_lock(&host->lock); + + while (len > 0) + { + //num = ((from + len) >= spi->chipsize) ? (spi->chipsize - from) : len; + num = len; + memcpy(ptr, (char *)host->iobase + from, num); + from += num; + ptr += num; + len -= num; + } + *retlen = (size_t)(ptr - buf); + result = 0; + + mutex_unlock(&host->lock); + return result; +} + + +int xmsfc_entry_quad_1addr(const struct xmsfc_params *params) +{ + unsigned int value = 0; + + // read st + writel(XMSFC_CMD_READ_ST2, XMSFC_REG_CMD); + writel(0, XMSFC_REG_RW_SR_BSEL); + writel(XMSFC_OP3, XMSFC_REG_OP); + while((readl(XMSFC_REG_ST) & XMSFC_OP3_OK) == 0); + value = readl(XMSFC_REG_SRR); + + writel((value << 8) | 0x0200 , XMSFC_REG_SRW); + writel(XMSFC_CMD_WRITE_ST, XMSFC_REG_CMD); + writel(1, XMSFC_REG_RW_SR_BSEL); + writel(XMSFC_OP4, XMSFC_REG_OP); + while((readl(XMSFC_REG_ST) & XMSFC_OP4_OK) == 0); + + writel(XMSFC_CMD_READ_ST2, XMSFC_REG_CMD); + writel(0, XMSFC_REG_RW_SR_BSEL); + writel(XMSFC_OP3, XMSFC_REG_OP); + while((readl(XMSFC_REG_ST) & XMSFC_OP3_OK) == 0); + value = readl(XMSFC_REG_SRR); + + if((value & 0x02) == 0) + { + return -1; + } + + writel(params->cmd_read, XMSFC_REG_CACHE_CMD); + writel(0x00, XMSFC_REG_MODE); + writel(0x01, XMSFC_REG_MODE); + while((readl(XMSFC_REG_MODE_ST) & 0x01) == 0); + + return 0; +} + + + +static int xmsfc_read_cmd(u8 cmd, void *data, size_t data_len) +{ + if(cmd == XMSFC_CMD_READ_JEDECID) + { + writel(XMSFC_CMD_READ_JEDECID, XMSFC_REG_CMD); + writel(2, XMSFC_REG_RW_SR_BSEL); + writel(XMSFC_OP3, XMSFC_REG_OP); + + udelay(1); + while((readl(XMSFC_REG_ST) & XMSFC_OP3_OK) == 0); + + *((u32*)data) = readl(XMSFC_REG_SRR) & 0x00FFFFFF; + } + return 0; +} + +static int xmsfc_driver_probe(struct platform_device * plat_dev) +{ + struct mtd_info *mtd; + int nr_parts = 0; + struct xmsfc_host *host; + const struct xmsfc_params *params; + struct mtd_partition *parts = NULL; + static char const *part_probes[] = { + "cmdlinepart", + NULL, + }; + + unsigned int jedec = 0; + + if(xmsfc_read_cmd(XMSFC_CMD_READ_JEDECID, &jedec, sizeof(jedec))) + { + printk(KERN_ERR "XMSFC: Failed to get idcodes\n"); + return -ENODEV; + } + + params = xmsfc_params_table; + for (; params->name != NULL; params++) + { + if ((params->jedec) == jedec) + break; + } + if (!params->name) + { + printk(KERN_WARNING "XMSFC: Unsupported flash IDs: %#x using default", jedec); + params = &xmsfc_params_default; + } + else + { + printk(KERN_INFO "XMSFC: flash name:%s size:%#x\n", params->name, params->size); + } + + if((params->flags & FLAG_QUAD_ONE_ADDR) == 1) + { + if(xmsfc_entry_quad_1addr(params)) + return -ENODEV; + printk(KERN_INFO "XMSFC: flash entry quad one addr\n"); + } + + host = kmalloc(sizeof(struct xmsfc_host), GFP_KERNEL); + if (!host) + return -ENOMEM; + memset(host, 0, sizeof(struct xmsfc_host)); + platform_set_drvdata(plat_dev, host); + + host->iobase = ioremap_nocache(XMSF_BASE_ADDR, XMSF_BASE_LEN); + if (!host->iobase) { + printk(KERN_ERR "spi buffer ioremap failed.\n"); + goto fail; + } + host->cmd_erase = params->cmd_erase; + host->cmd_write = params->cmd_write; + host->cmd_read = params->cmd_read; + + mutex_init(&host->lock); + mtd = host->mtd; + mtd->name = (char *)plat_dev->name; + mtd->type = MTD_NORFLASH; + mtd->writesize = 1; + mtd->flags = MTD_CAP_NORFLASH; + mtd->owner = THIS_MODULE; + mtd->_erase = xmsfc_reg_erase; + mtd->_write = xmsfc_reg_write; + mtd->_read = xmsfc_bus_read; + mtd->size = params->size; + mtd->erasesize = params->erasesize; + + nr_parts = parse_mtd_partitions(mtd, part_probes, &parts, 0); + + return mtd_device_register(mtd, parts, nr_parts) == 1 ? -ENODEV : 0; + +fail: + if (host->iobase) + iounmap(host->iobase); + kfree(host); + platform_set_drvdata(plat_dev, NULL); + return -EIO; +} +static int xmsfc_driver_remove(struct platform_device * plat_dev) +{ + struct xmsfc_host *host = platform_get_drvdata(plat_dev); + + mtd_device_unregister(host->mtd); + + if (host->iobase) + iounmap(host->iobase); + + kfree(host); + platform_set_drvdata(plat_dev, NULL); + + return 0; +} + +static void xmsfc_driver_shutdown(struct platform_device *pltdev) +{ + +} + +static struct platform_driver xmsfc_driver_pltdrv = { + .probe = xmsfc_driver_probe, + .remove = xmsfc_driver_remove, + .shutdown = xmsfc_driver_shutdown, + .driver.name = "xm_sfc", + .driver.owner = THIS_MODULE, + .driver.bus = &platform_bus_type, +}; + +static struct platform_device xmsfc_device_pltdev = { + .name = "xm_sfc", + .id = -1, +}; + +static int __init xmsfc_module_init(void) +{ + int result = 0; + + printk(KERN_DEBUG "XM Spi Flash Controller Device Driver Version 1.0\n"); + + result = platform_driver_register(&xmsfc_driver_pltdrv); + if (result < 0) + return result; + + result = platform_device_register(&xmsfc_device_pltdev); + if (result < 0) { + platform_driver_unregister(&xmsfc_driver_pltdrv); + return result; + } + + return result; +} + +static void __exit xmsfc_module_exit(void) +{ + platform_device_unregister(&xmsfc_device_pltdev); + platform_driver_unregister(&xmsfc_driver_pltdrv); +} + +module_init(xmsfc_module_init); +module_exit(xmsfc_module_exit); + +MODULE_LICENSE("GPL"); diff -uarN a/drivers/mtd/devices/xmsfc/xmsfc.h b/drivers/mtd/devices/xmsfc/xmsfc.h --- a/drivers/mtd/devices/xmsfc/xmsfc.h 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/mtd/devices/xmsfc/xmsfc.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,107 @@ +#ifndef _XMSFC_H_ +#define _XMSFC_H_ + + +#include +/*****************************************************************************/ + +#define _1K (0x400) +#define _2K (0x800) + +#define _4K (0x1000) +#define _8K (0x2000) +#define _16K (0x4000) +#define _32K (0x8000) + +#define _64K (0x10000) +#define _128K (0x20000) +#define _256K (0x40000) +#define _512K (0x80000) + +#define _1M (0x100000) +#define _2M (0x200000) +#define _4M (0x400000) +#define _8M (0x800000) + +#define _16M (0x1000000) +#define _32M (0x2000000) +#define _64M (0x4000000) + +#define INFINITE (0xFFFFFFFF) +/*****************************************************************************/ + +#define XMSFC_REG_BASE_ADDR __io_address(0x100F0000) + +#define XMSFC_REG_MODE (XMSFC_REG_BASE_ADDR + 0x00) +#define XMSFC_REG_ADDR (XMSFC_REG_BASE_ADDR + 0x04) /* Flash memoryַĴ; */ +#define XMSFC_REG_OP (XMSFC_REG_BASE_ADDR + 0x08) /* ָĴ; */ +#define XMSFC_REG_CMD (XMSFC_REG_BASE_ADDR + 0x0C) /* */ +#define XMSFC_REG_SRW (XMSFC_REG_BASE_ADDR + 0x10) /* flash־дĴ; */ +#define XMSFC_REG_WRNUM (XMSFC_REG_BASE_ADDR + 0x14) /* Flash д; */ +#define XMSFC_REG_RW_SR_BSEL (XMSFC_REG_BASE_ADDR + 0x18) /* Flashд״̬Ĵλѡ*/ +#define XMSFC_REG_DOUT (XMSFC_REG_BASE_ADDR + 0x34) /* flashݼĴ; */ +#define XMSFC_REG_ST (XMSFC_REG_BASE_ADDR + 0x38) /* Flash״̬Ĵ; */ +#define XMSFC_REG_SRR (XMSFC_REG_BASE_ADDR + 0x3C) /* flash־Ĵ; */ +#define XMSFC_REG_MODE_ST (XMSFC_REG_BASE_ADDR + 0x4C) +#define XMSFC_REG_CACHE_CMD (XMSFC_REG_BASE_ADDR + 0x80) + +#define XMSFC_REG_BUF (XMSFC_REG_BASE_ADDR + 0x400) /* */ +#define XMSFC_REG_BUF_SIZE 256 +#define XMSFC_REG_BASE_LEN 0x800 + +#define XMSF_BASE_ADDR 0x08000000 +#define XMSF_BASE_LEN 0x01000000 /*16MB*/ + +#define XMSFC_OP1_OK 0x01 // +#define XMSFC_OP2_OK 0x02 // +#define XMSFC_OP3_OK 0x04 // +#define XMSFC_OP4_OK 0x08 // +#define XMSFC_OP5_OK 0x10 // +#define XMSFC_OP6_OK 0x20 // + +// XMSFCASH operation command +#define XMSFC_OP1 0x01 // +#define XMSFC_OP2 0x02 // +#define XMSFC_OP3 0x03 // +#define XMSFC_OP4 0x04 // +#define XMSFC_OP5 0x05 // +#define XMSFC_OP6 0x06 // + +/*#define XMSFC_CMD_WRITE_DATA 0x02*/ +/*#define XMSFC_CMD_READ_DATA 0x03*/ +#define XMSFC_CMD_READ_JEDECID 0x9F +#define XMSFC_CMD_WRITE_ST 0x01 +#define XMSFC_CMD_READ_ST2 0x35 + + +#define DBG_MSG(_fmt, arg...) printk(KERN_INFO "%s(%d): " _fmt, __FILE__, __LINE__, ##arg); + +#define MTD_TO_HOST(_mtd) ((struct xmsfc_host *)(_mtd)) + +#define FLAG_QUAD_ONE_ADDR 0x01 + +struct xmsfc_host { + struct mtd_info mtd[1]; + void __iomem *iobase; + struct mutex lock; + unsigned char cmd_erase; + unsigned char cmd_write; + unsigned char cmd_read; + unsigned char dummy_byte; +}; + +struct xmsfc_params { + const char *name; + unsigned int jedec; + unsigned int size; + unsigned int erasesize; + unsigned char cmd_erase; + unsigned char cmd_write; + unsigned char cmd_read; + unsigned char cmd_quad_write; + unsigned char cmd_quad_read; + unsigned char flags; +}; + + +#endif diff -uarN a/drivers/mtd/devices/xmsfc/xmsfc_params.c b/drivers/mtd/devices/xmsfc/xmsfc_params.c --- a/drivers/mtd/devices/xmsfc/xmsfc_params.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/mtd/devices/xmsfc/xmsfc_params.c 2019-02-14 05:41:45.000000000 +0300 @@ -0,0 +1,14 @@ +#include +#include "xmsfc_v2.h" + +const struct xmsfc_params xmsfc_params_table[] = { + {"W25Q64CV", 0xef4017, _8M, _64K, 0xD8, 0x02, 0x03, 0x32, 0x6B, 0}, + {"MX25L6405D", 0xc22017, _8M, _64K, 0xD8, 0x02, 0x03, 0x00, 0x00, 0}, + {"W25Q128BV", 0xef4018, _16M, _64K, 0xD8, 0x02, 0x03, 0x00, 0x00, 0}, + {"MX25L12835F", 0xc22018, _16M, _64K, 0xD8, 0x02, 0x03, 0x00, 0x00, 0}, + {"EN25QH64A", 0x1c7017, _8M, _64K, 0xD8, 0x02, 0x03, 0x32, 0x6B, 0}, + {"XM25Q64AHIG", 0x207017, _8M, _64K, 0xD8, 0x02, 0x03, 0x32, 0x6B, 0}, +}; +const struct xmsfc_params xmsfc_params_default = { + "DEFAULT", 0x000000, _8M, _64K, 0xD8, 0x02, 0x03, 0x00, 0x00, 0 +}; diff -uarN a/drivers/mtd/devices/xmsfc/xmsfc_v2.c b/drivers/mtd/devices/xmsfc/xmsfc_v2.c --- a/drivers/mtd/devices/xmsfc/xmsfc_v2.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/mtd/devices/xmsfc/xmsfc_v2.c 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,355 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../mtdcore.h" + +#include "xmsfc_v2.h" + +extern const struct xmsfc_params xmsfc_params_table[]; +extern const struct xmsfc_params xmsfc_params_default; + +static inline void spi_flash_read_ready(u8 dummy_byte) +{ + if(dummy_byte == 0) + { + writel(0x04, XM_SFC_V2_CFG1); + writel(0x02, XM_SFC_V2_CFG2); + } + else + { + writel(0x0C, XM_SFC_V2_CFG1); + writel(0x02, XM_SFC_V2_CFG2); + } + +} + +static int xmsfc_reg_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + unsigned long long offset = instr->addr; + unsigned long long length = instr->len; + unsigned int timeout = 0x10000000; + struct xmsfc_host *host = MTD_TO_HOST(mtd); + + if (offset + length > mtd->size) { + DBG_MSG("erase area out of range of mtd.\n"); + return -EINVAL; + } + + if ((unsigned int)offset & (mtd->erasesize-1)) { + DBG_MSG("erase start address is not alignment.\n"); + return -EINVAL; + } + // + if ((unsigned int)length & (mtd->erasesize-1)) { + DBG_MSG("erase length is not alignment.\n"); + return -EINVAL; + } + + mutex_lock(&host->lock); + writel(0x05, XM_SFC_V2_CFG1); + writel(0x02, XM_SFC_V2_CFG2); + writel(0x05, XM_SFC_V2_PST_CMD); + writel(host->cmd_erase, XM_SFC_V2_CMD); + while (length) + { + writel(offset, XM_SFC_V2_ADDR); + writel(FL_OP1, XM_SFC_V2_OP); + + while((readl(XM_SFC_V2_ST) & FL_OP1_OK) == 0) + { + if(--timeout == 0) + { + instr->state = MTD_ERASE_FAILED; + mutex_unlock(&host->lock); + return -EIO; + } + } + + offset += mtd->erasesize; + length -= mtd->erasesize; + } + instr->state = MTD_ERASE_DONE; + mutex_unlock(&host->lock); + mtd_erase_callback(instr); + + return 0; +} + +static int xmsfc_reg_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct xmsfc_host *host = MTD_TO_HOST(mtd); + unsigned char *ptr = (unsigned char *)buf; + int num = 0; + int remain = 0; + int index = 0; + + if ((to + len) > mtd->size) { + DBG_MSG("write data out of range.\n"); + return -EINVAL; + } + + *retlen = 0; + if (!len) { + DBG_MSG("write length is 0.\n"); + return 0; + } + mutex_lock(&host->lock); + writel(0x05, XM_SFC_V2_CFG1); + writel(0x02, XM_SFC_V2_CFG2); + writel(0x05, XM_SFC_V2_PST_CMD); + writel(host->cmd_write, XM_SFC_V2_CMD); + + while(len > 0) + { + remain = (to % XM_SFC_V2_BUF_SIZE); + num = ((len >= XM_SFC_V2_BUF_SIZE - remain) ? XM_SFC_V2_BUF_SIZE - remain : len); + + writel(to, XM_SFC_V2_ADDR); + writel(num - 1, XM_SFC_V2_RW_NUM); + + index = 0; + while(index < num) + { + writel(*(unsigned int *)(ptr + index), XM_SFC_V2_RAM + index); + index += 4; + } + + writel(FL_OP4, XM_SFC_V2_OP); + while((readl(XM_SFC_V2_ST) & FL_OP4_OK) == 0); + + to += num; + ptr += num; + len -= num; + } + *retlen = (size_t)(ptr - buf); + + mutex_unlock(&host->lock); + return 0; +} +static int xmsfc_bus_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + int num; + int result = -EIO; + unsigned char *ptr = buf; + struct xmsfc_host *host = MTD_TO_HOST(mtd); + + if ((from + len) > mtd->size) { + DBG_MSG("read area out of range.\n"); + return -EINVAL; + } + + *retlen = 0; + if (!len) { + DBG_MSG("read length is 0.\n"); + return 0; + } + + mutex_lock(&host->lock); + spi_flash_read_ready(host->dummy_byte); + + while (len > 0) + { + //num = ((from + len) >= spi->chipsize) ? (spi->chipsize - from) : len; + num = len; + memcpy(ptr, (char *)host->iobase + from, num); + from += num; + ptr += num; + len -= num; + } + *retlen = (size_t)(ptr - buf); + result = 0; + + mutex_unlock(&host->lock); + return result; +} + +static int xmsfc_read_cmd(u8 cmd, void *data, size_t data_len) +{ + if(cmd == SPI_NOR_CMD_READ_JEDECID) + { + writel(0x00, XM_SFC_V2_CFG1); + writel(0x00, XM_SFC_V2_CFG2); + writel(SPI_NOR_CMD_READ_JEDECID, XM_SFC_V2_CMD); + writel(2, XM_SFC_V2_RW_NUM); + writel(FL_OP3, XM_SFC_V2_OP); + + udelay(1); + while((readl(XM_SFC_V2_ST) & FL_OP3_OK) == 0); + + *((u32*)data) = readl(XM_SFC_V2_R_SR_ID) & 0x00FFFFFF; + } + return 0; +} + +static int xmsfc_driver_probe(struct platform_device * plat_dev) +{ + struct mtd_info *mtd; + int nr_parts = 0; + struct xmsfc_host *host; + const struct xmsfc_params *params; + struct mtd_partition *parts = NULL; + static char const *part_probes[] = { + "cmdlinepart", + NULL, + }; + + unsigned int jedec = 0; + + gpio_write(GPIO_DRIVE_8MA | GPIO_MUX2_EN, GPIO_FLASH_CLK); + gpio_write(GPIO_DRIVE_8MA | GPIO_MUX2_EN, GPIO_FLASH_CSN); + gpio_write(GPIO_DRIVE_8MA | GPIO_MUX2_EN, GPIO_FLASH_DI); + gpio_write(GPIO_DRIVE_8MA | GPIO_MUX2_EN, GPIO_FLASH_DO); + gpio_write(GPIO_DRIVE_8MA | GPIO_MUX2_EN, GPIO_FLASH_WPN); + gpio_write(GPIO_DRIVE_8MA | GPIO_MUX2_EN, GPIO_FLASH_HOLD); + + writel(readl(XM_SFC_V2_CTRL) | (1 << 7), XM_SFC_V2_CTRL); + + if(xmsfc_read_cmd(SPI_NOR_CMD_READ_JEDECID, &jedec, sizeof(jedec))) + { + printk(KERN_ERR "XMSFCV2: Failed to get idcodes\n"); + return -ENODEV; + } + + params = xmsfc_params_table; + for (; params->name != NULL; params++) + { + if ((params->jedec) == jedec) + break; + } + if (!params->name) + { + printk(KERN_WARNING "XMSFCV2: Unsupported flash IDs: %#x using default", jedec); + params = &xmsfc_params_default; + } + else + { + printk(KERN_INFO "XMSFCV2: flash name:%s size:%#x\n", params->name, params->size); + } + + + host = kmalloc(sizeof(struct xmsfc_host), GFP_KERNEL); + if (!host) + return -ENOMEM; + memset(host, 0, sizeof(struct xmsfc_host)); + platform_set_drvdata(plat_dev, host); + + host->iobase = ioremap_nocache(XMSF_BASE_ADDR, XMSF_BASE_LEN); + if (!host->iobase) { + printk(KERN_ERR "spi buffer ioremap failed.\n"); + goto fail; + } + + if(readl(XM_SFC_V2_MODE_ST) == 0) + { + host->cmd_erase = params->cmd_erase; + host->cmd_write = params->cmd_write; + host->cmd_read = params->cmd_read; + host->dummy_byte = 0; + } + else //目前只支持 地址1线quad spi + { + host->cmd_erase = params->cmd_erase; + host->cmd_write = params->cmd_quad_write; + host->cmd_read = params->cmd_quad_read; + host->dummy_byte = 1; + } + + mutex_init(&host->lock); + mtd = host->mtd; + mtd->name = (char *)plat_dev->name; + mtd->type = MTD_NORFLASH; + mtd->writesize = 1; + mtd->flags = MTD_CAP_NORFLASH; + mtd->owner = THIS_MODULE; + mtd->_erase = xmsfc_reg_erase; + mtd->_write = xmsfc_reg_write; + mtd->_read = xmsfc_bus_read; + mtd->size = params->size; + mtd->erasesize = params->erasesize; + + nr_parts = parse_mtd_partitions(mtd, part_probes, &parts, 0); + + return mtd_device_register(mtd, parts, nr_parts) == 1 ? -ENODEV : 0; + +fail: + if (host->iobase) + iounmap(host->iobase); + kfree(host); + platform_set_drvdata(plat_dev, NULL); + return -EIO; +} +static int xmsfc_driver_remove(struct platform_device * plat_dev) +{ + struct xmsfc_host *host = platform_get_drvdata(plat_dev); + + mtd_device_unregister(host->mtd); + + if (host->iobase) + iounmap(host->iobase); + + kfree(host); + platform_set_drvdata(plat_dev, NULL); + + return 0; +} + +static void xmsfc_driver_shutdown(struct platform_device *pltdev) +{ + +} + +static struct platform_driver xmsfc_driver_pltdrv = { + .probe = xmsfc_driver_probe, + .remove = xmsfc_driver_remove, + .shutdown = xmsfc_driver_shutdown, + .driver.name = "xm_sfc", + .driver.owner = THIS_MODULE, + .driver.bus = &platform_bus_type, +}; + +static struct platform_device xmsfc_device_pltdev = { + .name = "xm_sfc", + .id = -1, +}; + +static int __init xmsfc_module_init(void) +{ + int result = 0; + + printk(KERN_DEBUG "XM Spi Flash Controller Device Driver Version 1.0\n"); + + result = platform_driver_register(&xmsfc_driver_pltdrv); + if (result < 0) + return result; + + result = platform_device_register(&xmsfc_device_pltdev); + if (result < 0) { + platform_driver_unregister(&xmsfc_driver_pltdrv); + return result; + } + + return result; +} + +static void __exit xmsfc_module_exit(void) +{ + platform_device_unregister(&xmsfc_device_pltdev); + platform_driver_unregister(&xmsfc_driver_pltdrv); +} + +module_init(xmsfc_module_init); +module_exit(xmsfc_module_exit); + +MODULE_LICENSE("GPL"); diff -uarN a/drivers/mtd/devices/xmsfc/xmsfc_v2.h b/drivers/mtd/devices/xmsfc/xmsfc_v2.h --- a/drivers/mtd/devices/xmsfc/xmsfc_v2.h 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/mtd/devices/xmsfc/xmsfc_v2.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,121 @@ +#ifndef _XMSFC_V2_H_ +#define _XMSFC_V2_H_ + + +#include +/*****************************************************************************/ + +#define _1K (0x400) +#define _2K (0x800) + +#define _4K (0x1000) +#define _8K (0x2000) +#define _16K (0x4000) +#define _32K (0x8000) + +#define _64K (0x10000) +#define _128K (0x20000) +#define _256K (0x40000) +#define _512K (0x80000) + +#define _1M (0x100000) +#define _2M (0x200000) +#define _4M (0x400000) +#define _8M (0x800000) + +#define _16M (0x1000000) +#define _32M (0x2000000) +#define _64M (0x4000000) + +#define INFINITE (0xFFFFFFFF) +/*****************************************************************************/ + +#define XM_SFC_V2_CTRL __io_address(0x100F4000) +#define XM_SFC_V2_CFG1 __io_address(0x100F4004) +#define XM_SFC_V2_CFG2 __io_address(0x100F4008) +#define XM_SFC_V2_ADDR __io_address(0x100F400c) +#define XM_SFC_V2_OP __io_address(0x100F4010) +#define XM_SFC_V2_CMD __io_address(0x100F4014) +#define XM_SFC_V2_SRW __io_address(0x100F4018) +#define XM_SFC_V2_RW_NUM __io_address(0x100F401c) +#define XM_SFC_V2_PRE_CMD __io_address(0x100F4020) +#define XM_SFC_V2_PST_CMD __io_address(0x100F4024) +#define XM_SFC_V2_TDEL __io_address(0x100F4028) +#define XM_SFC_V2_ST __io_address(0x100F402c) +#define XM_SFC_V2_R_SR_ID __io_address(0x100F4030) +#define XM_SFC_V2_RINT __io_address(0x100F4034) +#define XM_SFC_V2_INT_MSK __io_address(0x100F4038) +#define XM_SFC_V2_INT_ST __io_address(0x100F403c) +#define XM_SFC_V2_MODE_ST __io_address(0x100F4040) +#define XM_SFC_V2_CACHE_CMD __io_address(0x100F4044) +#define XM_SFC_V2_CACHE_BBT __io_address(0x100F4048) +#define XM_SFC_V2_RAM __io_address(0x100F6000) + + +#define XM_SFC_V2_BUF_SIZE 256 +#define XM_SFC_V2_BASE_LEN 0x800 + +#define XMSF_BASE_ADDR 0x60000000 +#define XMSF_BASE_LEN 0x01000000 /*16MB*/ + +#define SPI_NOR_CMD_WRITE_ST 0x01 +#define SPI_NOR_CMD_WRITE_DATA 0x02 +#define SPI_NOR_CMD_READ_DATA 0x03 +#define SPI_NOR_CMD_READ_ST 0x05 +#define SPI_NOR_CMD_READ_ST2 0x35 +#define SPI_NOR_CMD_READ_JEDECID 0x9F /*读ID*/ + +#define FL_OP1 0x01 +#define FL_OP2 0x02 +#define FL_OP3 0x03 +#define FL_OP4 0x04 +#define FL_OP5 0x05 +#define FL_OP6 0x06 +#define FL_OP7 0x07 +#define FL_OP8 0x08 +#define FL_OP9 0x09 +#define FL_OP10 0x0A + +#define FL_OP1_OK 0x01 +#define FL_OP2_OK 0x02 +#define FL_OP3_OK 0x04 +#define FL_OP4_OK 0x08 +#define FL_OP5_OK 0x10 +#define FL_OP6_OK 0x20 +#define FL_OP7_OK 0x40 +#define FL_OP8_OK 0x80 +#define FL_OP9_OK 0x100 +#define FL_OP10_OK 0x200 + + +#define DBG_MSG(_fmt, arg...) printk(KERN_INFO "%s(%d): " _fmt, __FILE__, __LINE__, ##arg); + +#define MTD_TO_HOST(_mtd) ((struct xmsfc_host *)(_mtd)) + +#define FLAG_QUAD_ONE_ADDR 0x01 + +struct xmsfc_host { + struct mtd_info mtd[1]; + void __iomem *iobase; + struct mutex lock; + unsigned char cmd_erase; + unsigned char cmd_write; + unsigned char cmd_read; + unsigned char dummy_byte; +}; + +struct xmsfc_params { + const char *name; + unsigned int jedec; + unsigned int size; + unsigned int erasesize; + unsigned char cmd_erase; + unsigned char cmd_write; + unsigned char cmd_read; + unsigned char cmd_quad_write; + unsigned char cmd_quad_read; + unsigned char flags; +}; + + +#endif diff -uarN a/drivers/net/Kconfig b/drivers/net/Kconfig --- a/drivers/net/Kconfig 2016-08-28 13:19:20.000000000 +0300 +++ b/drivers/net/Kconfig 2018-11-21 06:44:38.000000000 +0300 @@ -358,4 +358,50 @@ source "drivers/net/hyperv/Kconfig" + +#------------------------------------- + + +# +# Gigabit Ethernet +# + +menuconfig NETDEV_1000 + bool "Ethernet (1000 Mbit)" + depends on !UML + default y + ---help--- + Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common + type of Local Area Network (LAN) in universities and companies. + + Say Y here to get to see options for Gigabit Ethernet drivers. + This option alone does not add any kernel code. + Note that drivers supporting both 100 and 1000 MBit may be listed + under "Ethernet (10 or 100MBit)" instead. + + If you say N, all options in this submenu will be skipped and disabled. + +if NETDEV_1000 + + source "drivers/net/xmmac/Kconfig" + +endif + +#------------------------------------ + + + + endif # NETDEVICES + + + + + + + + + + + + diff -uarN a/drivers/net/Makefile b/drivers/net/Makefile --- a/drivers/net/Makefile 2016-08-28 13:19:20.000000000 +0300 +++ b/drivers/net/Makefile 2018-11-21 06:44:38.000000000 +0300 @@ -72,3 +72,6 @@ obj-$(CONFIG_HYPERV_NET) += hyperv/ obj-$(CONFIG_NTB_NETDEV) += ntb_netdev.o + +obj-$(CONFIG_XMMAC_ETH) += xmmac/ + diff -uarN a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c --- a/drivers/net/phy/phy_device.c 2016-08-28 13:19:20.000000000 +0300 +++ b/drivers/net/phy/phy_device.c 2018-12-18 08:28:41.000000000 +0300 @@ -339,7 +339,7 @@ return ERR_PTR(r); /* If the phy_id is mostly Fs, there is no device there */ - if ((phy_id & 0x1fffffff) == 0x1fffffff) + if (((phy_id & 0x1fffffff) == 0x1fffffff) || ((phy_id & 0x1fffffff) == 0x0)) return NULL; dev = phy_device_create(bus, addr, phy_id, is_c45, &c45_ids); diff -uarN a/drivers/net/xmmac/Kconfig b/drivers/net/xmmac/Kconfig --- a/drivers/net/xmmac/Kconfig 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/Kconfig 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,57 @@ +config XMMAC_ETH + tristate "xm550 10/100/1000 Ethernet driver" + select MII + select PHYLIB + select CRC32 + depends on NETDEVICES && HAS_IOMEM + help + This is the driver for the Ethernet IPs are built around a + Synopsys IP Core and only tested on the STMicroelectronics + platforms. + +if STMMAC_ETH + +config STMMAC_DA + bool "STMMAC DMA arbitration scheme" + default n + help + Selecting this option, rx has priority over Tx (only for Giga + Ethernet device). + By default, the DMA arbitration scheme is based on Round-robin + (rx:tx priority is 1:1). + +config STMMAC_DUAL_MAC + bool "STMMAC: dual mac support (EXPERIMENTAL)" + default n + depends on EXPERIMENTAL && STMMAC_ETH && !STMMAC_TIMER + help + Some ST SoCs (for example the stx7141 and stx7200c2) have two + Ethernet Controllers. This option turns on the second Ethernet + device on this kind of platforms. + +config STMMAC_TIMER + bool "STMMAC Timer optimisation" + default n + depends on RTC_HCTOSYS_DEVICE + help + Use an external timer for mitigating the number of network + interrupts. Currently, for SH architectures, it is possible + to use the TMU channel 2 and the SH-RTC device. + +choice + prompt "Select Timer device" + depends on STMMAC_TIMER + +config STMMAC_TMU_TIMER + bool "TMU channel 2" + depends on CPU_SH4 + help + +config STMMAC_RTC_TIMER + bool "Real time clock" + depends on RTC_CLASS + help + +endchoice + +endif diff -uarN a/drivers/net/xmmac/Makefile b/drivers/net/xmmac/Makefile --- a/drivers/net/xmmac/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/Makefile 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,5 @@ +obj-$(CONFIG_XMMAC_ETH) += xmmac.o +stmmac-$(CONFIG_STMMAC_TIMER) += stmmac_timer.o +xmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \ + dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \ + dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o $(stmmac-y) diff -uarN a/drivers/net/xmmac/common.h b/drivers/net/xmmac/common.h --- a/drivers/net/xmmac/common.h 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/common.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,250 @@ +/******************************************************************************* + STMMAC Common Header File + + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) +#define STMMAC_VLAN_TAG_USED +#include +#endif + +#include "descs.h" + +#undef CHIP_DEBUG_PRINT +/* Turn-on extra printk debug for MAC core, dma and descriptors */ +/* #define CHIP_DEBUG_PRINT */ + +#ifdef CHIP_DEBUG_PRINT +#define CHIP_DBG(fmt, args...) printk(fmt, ## args) +#else +#define CHIP_DBG(fmt, args...) do { } while (0) +#endif + +#undef FRAME_FILTER_DEBUG +/* #define FRAME_FILTER_DEBUG */ + +struct stmmac_extra_stats { + /* ******************************************* + * Adited by ZengChuanJie + * ******************************************/ + /* Transmit errors */ + unsigned long tx_underflow ____cacheline_aligned; + unsigned long tx_carrier; + unsigned long tx_losscarrier; + unsigned long tx_deferred; + unsigned long tx_vlan; + unsigned long tx_jabber; + unsigned long tx_frame_flushed; + unsigned long tx_payload_error; + unsigned long tx_ip_header_error; + /* Receive errors */ + unsigned long rx_desc; + unsigned long rx_collision; + unsigned long rx_crc; + unsigned long rx_length; + unsigned long rx_gmac_overflow; + unsigned long rx_watchdog; + unsigned long da_rx_filter_fail; + unsigned long sa_rx_filter_fail; + unsigned long rx_missed_cntr; + unsigned long rx_overflow_cntr; + unsigned long rx_vlan; + /******* end *****************/ + /* Tx/Rx IRQ errors */ + unsigned long tx_undeflow_irq; + unsigned long tx_process_stopped_irq; + unsigned long tx_jabber_irq; + unsigned long rx_overflow_irq; + unsigned long rx_buf_unav_irq; + unsigned long rx_process_stopped_irq; + unsigned long rx_watchdog_irq; + unsigned long tx_early_irq; + unsigned long fatal_bus_error_irq; + /* Extra info */ + unsigned long threshold; + unsigned long tx_pkt_n; + unsigned long rx_pkt_n; + unsigned long poll_n; + unsigned long sched_timer_n; + unsigned long normal_irq_n; +}; + +#define HASH_TABLE_SIZE 64 +#define PAUSE_TIME 0x200 + +/* Flow Control defines */ +#define FLOW_OFF 0 +#define FLOW_RX 1 +#define FLOW_TX 2 +#define FLOW_AUTO (FLOW_TX | FLOW_RX) + +#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */ + +enum rx_frame_status { /* IPC status */ + good_frame = 0, + discard_frame = 1, + csum_none = 2, + llc_snap = 4, +}; + +enum tx_dma_irq_status { + tx_hard_error = 1, + tx_hard_error_bump_tc = 2, + handle_tx_rx = 3, +}; + +/* GMAC TX FIFO is 8K, Rx FIFO is 16K */ +#define BUF_SIZE_16KiB 16384 +#define BUF_SIZE_8KiB 8192 +#define BUF_SIZE_4KiB 4096 +#define BUF_SIZE_2KiB 2048 + +/* Power Down and WOL */ +#define PMT_NOT_SUPPORTED 0 +#define PMT_SUPPORTED 1 + +/* Common MAC defines */ +#define MAC_CTRL_REG 0x00000000 /* MAC Control */ +#define MAC_ENABLE_TX 0x00000008 /* Transmitter Enable */ +#define MAC_RNABLE_RX 0x00000004 /* Receiver Enable */ + +/* MAC Management Counters register */ +#define MMC_CONTROL 0x00000100 /* MMC Control */ +#define MMC_HIGH_INTR 0x00000104 /* MMC High Interrupt */ +#define MMC_LOW_INTR 0x00000108 /* MMC Low Interrupt */ +#define MMC_HIGH_INTR_MASK 0x0000010c /* MMC High Interrupt Mask */ +#define MMC_LOW_INTR_MASK 0x00000110 /* MMC Low Interrupt Mask */ + +#define MMC_CONTROL_MAX_FRM_MASK 0x0003ff8 /* Maximum Frame Size */ +#define MMC_CONTROL_MAX_FRM_SHIFT 3 +#define MMC_CONTROL_MAX_FRAME 0x7FF + +struct stmmac_desc_ops { + /* DMA RX descriptor ring initialization */ + void (*init_rx_desc) (struct dma_desc *p, unsigned int ring_size, + int disable_rx_ic); + /* DMA TX descriptor ring initialization */ + void (*init_tx_desc) (struct dma_desc *p, unsigned int ring_size); + + /* Invoked by the xmit function to prepare the tx descriptor */ + void (*prepare_tx_desc) (struct dma_desc *p, int is_fs, int len, + int csum_flag); + /* Set/get the owner of the descriptor */ + void (*set_tx_owner) (struct dma_desc *p); + int (*get_tx_owner) (struct dma_desc *p); + /* Invoked by the xmit function to close the tx descriptor */ + void (*close_tx_desc) (struct dma_desc *p); + /* Clean the tx descriptor as soon as the tx irq is received */ + void (*release_tx_desc) (struct dma_desc *p); + /* Clear interrupt on tx frame completion. When this bit is + * set an interrupt happens as soon as the frame is transmitted */ + void (*clear_tx_ic) (struct dma_desc *p); + /* Last tx segment reports the transmit status */ + int (*get_tx_ls) (struct dma_desc *p); + /* Return the transmit status looking at the TDES1 */ + int (*tx_status) (void *data, struct stmmac_extra_stats *x, + struct dma_desc *p, void __iomem *ioaddr); + /* Get the buffer size from the descriptor */ + int (*get_tx_len) (struct dma_desc *p); + /* Handle extra events on specific interrupts hw dependent */ + int (*get_rx_owner) (struct dma_desc *p); + void (*set_rx_owner) (struct dma_desc *p); + /* Get the receive frame size */ + int (*get_rx_frame_len) (struct dma_desc *p); + /* Return the reception status looking at the RDES1 */ + int (*rx_status) (void *data, struct stmmac_extra_stats *x, + struct dma_desc *p); +}; + +struct stmmac_dma_ops { + /* DMA core initialization */ + int (*init) (void __iomem *ioaddr, int pbl, u32 dma_tx, u32 dma_rx); + /* Dump DMA registers */ + void (*dump_regs) (void __iomem *ioaddr); + /* Set tx/rx threshold in the csr6 register + * An invalid value enables the store-and-forward mode */ + void (*dma_mode) (void __iomem *ioaddr, int txmode, int rxmode); + /* To track extra statistic (if supported) */ + void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x, + void __iomem *ioaddr); + void (*enable_dma_transmission) (void __iomem *ioaddr); + void (*enable_dma_irq) (void __iomem *ioaddr); + void (*disable_dma_irq) (void __iomem *ioaddr); + void (*start_tx) (void __iomem *ioaddr); + void (*stop_tx) (void __iomem *ioaddr); + void (*start_rx) (void __iomem *ioaddr); + void (*stop_rx) (void __iomem *ioaddr); + int (*dma_interrupt) (void __iomem *ioaddr, + struct stmmac_extra_stats *x); +}; + +struct stmmac_ops { + /* MAC core initialization */ + void (*core_init) (void __iomem *ioaddr) ____cacheline_aligned; + /* Support checksum offload engine */ + int (*rx_coe) (void __iomem *ioaddr); + /* Dump MAC registers */ + void (*dump_regs) (void __iomem *ioaddr); + /* Handle extra events on specific interrupts hw dependent */ + void (*host_irq_status) (void __iomem *ioaddr); + /* Multicast filter setting */ + void (*set_filter) (struct net_device *dev); + /* Flow control setting */ + void (*flow_ctrl) (void __iomem *ioaddr, unsigned int duplex, + unsigned int fc, unsigned int pause_time); + /* Set power management mode (e.g. magic frame) */ + void (*pmt) (void __iomem *ioaddr, unsigned long mode); + /* Set/Get Unicast MAC addresses */ + void (*set_umac_addr) (void __iomem *ioaddr, unsigned char *addr, + unsigned int reg_n); + void (*get_umac_addr) (void __iomem *ioaddr, unsigned char *addr, + unsigned int reg_n); +}; + +struct mac_link { + int port; + int duplex; + int speed; +}; + +struct mii_regs { + unsigned int addr; /* MII Address */ + unsigned int data; /* MII Data */ +}; + +struct mac_device_info { + const struct stmmac_ops *mac; + const struct stmmac_desc_ops *desc; + const struct stmmac_dma_ops *dma; + struct mii_regs mii; /* MII register Addresses */ + struct mac_link link; +}; + +struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr); +struct mac_device_info *dwmac100_setup(void __iomem *ioaddr); + +extern void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6], + unsigned int high, unsigned int low); +extern void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, + unsigned int high, unsigned int low); +extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr); diff -uarN a/drivers/net/xmmac/descs.h b/drivers/net/xmmac/descs.h --- a/drivers/net/xmmac/descs.h 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/descs.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,167 @@ +/******************************************************************************* + Header File to describe the DMA descriptors. + Enhanced descriptors have been in case of DWMAC1000 Cores. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ +struct dma_desc { + /* Receive descriptor */ + union { + struct { + /* RDES0 */ + u32 rx_payload_error:1; + u32 crc_error:1; + u32 dribbling:1; + u32 mii_error:1; + u32 receive_watchdog:1; + u32 frame_type:1; + u32 collision:1; + u32 IPC:1; /* IPC Checksum Error or Giant Frame */ + u32 last_descriptor:1; + u32 first_descriptor:1; + u32 vlan_tag:1; + u32 overflow_error:1; + u32 length_error:1; + u32 SAF:1; /* source Address Filter Fail */ + u32 descriptor_error:1; + u32 error_summary:1; + u32 frame_length:14; + u32 filtering_fail:1; + u32 own:1; + /* RDES1 */ + u32 buffer1_size:11; + u32 buffer2_size:11; + u32 reserved2:2; + u32 second_address_chained:1; + u32 end_ring:1; + u32 reserved3:5; + u32 disable_ic:1; + } rx; + struct { + /* RDES0 */ + u32 payload_csum_error:1; + u32 crc_error:1; + u32 dribbling:1; + u32 error_gmii:1; + u32 receive_watchdog:1; + u32 frame_type:1; + u32 late_collision:1; + u32 ipc_csum_error:1; + u32 last_descriptor:1; + u32 first_descriptor:1; + u32 vlan_tag:1; + u32 overflow_error:1; + u32 length_error:1; + u32 sa_filter_fail:1; + u32 descriptor_error:1; + u32 error_summary:1; + u32 frame_length:14; + u32 da_filter_fail:1; + u32 own:1; + /* RDES1 */ + u32 buffer1_size:13; + u32 reserved1:1; + u32 second_address_chained:1; + u32 end_ring:1; + u32 buffer2_size:13; + u32 reserved2:2; + u32 disable_ic:1; + } erx; /* -- enhanced -- */ + + /* Transmit descriptor */ + struct { + /* TDES0 */ + u32 deferred:1; + u32 underflow_error:1; + u32 excessive_deferral:1; + u32 collision_count:4; + u32 vlan_frame:1; + u32 excessive_collisions:1; + u32 late_collision:1; + u32 no_carrier:1; + u32 loss_carrier:1; + u32 payload_checksum_err:1; + u32 frame_flushed:1; + u32 jabber_timeout:1; + u32 error_summary:1; + u32 ip_header_error:1; + u32 ttss:1; + u32 reserved2:13; + u32 own:1; + /* TDES1 */ + u32 buffer1_size:11; + u32 buffer2_size:11; + u32 reserved3:1; + u32 disable_padding:1; + u32 second_address_chained:1; + u32 end_ring:1; + u32 crc_disable:1; + u32 reserved4:2; + u32 first_segment:1; + u32 last_segment:1; + u32 interrupt:1; + } tx; + struct { + /* TDES0 */ + u32 deferred:1; + u32 underflow_error:1; + u32 excessive_deferral:1; + u32 collision_count:4; + u32 vlan_frame:1; + u32 excessive_collisions:1; + u32 late_collision:1; + u32 no_carrier:1; + u32 loss_carrier:1; + u32 payload_error:1; + u32 frame_flushed:1; + u32 jabber_timeout:1; + u32 error_summary:1; + u32 ip_header_error:1; + u32 time_stamp_status:1; + u32 reserved1:2; + u32 second_address_chained:1; + u32 end_ring:1; + u32 checksum_insertion:2; + u32 reserved2:1; + u32 time_stamp_enable:1; + u32 disable_padding:1; + u32 crc_disable:1; + u32 first_segment:1; + u32 last_segment:1; + u32 interrupt:1; + u32 own:1; + /* TDES1 */ + u32 buffer1_size:13; + u32 reserved3:3; + u32 buffer2_size:13; + u32 reserved4:3; + } etx; /* -- enhanced -- */ + } des01; + unsigned int des2; + unsigned int des3; +}; + +/* Transmit checksum insertion control */ +enum tdes_csum_insertion { + cic_disabled = 0, /* Checksum Insertion Control */ + cic_only_ip = 1, /* Only IP header */ + cic_no_pseudoheader = 2, /* IP header but pseudoheader + * is not calculated */ + cic_full = 3, /* IP header and pseudoheader */ +}; diff -uarN a/drivers/net/xmmac/dwmac100.h b/drivers/net/xmmac/dwmac100.h --- a/drivers/net/xmmac/dwmac100.h 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/dwmac100.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,172 @@ +/******************************************************************************* + MAC 10/100 Header File + + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include +#include "common.h" + +/*---------------------------------------------------------------------------- + * MAC BLOCK defines + *---------------------------------------------------------------------------*/ +/* MAC CSR offset */ +#define MAC_CONTROL 0x00000000 /* MAC Control */ + +/********************************************************************* + * 1.Edited by ZengChuanJie + ********************************************************************/ +#define MAC_FRAME_FLT 0x00000004 /* MAC Frame Filter */ +#define MAC_HASH_HIGH 0x00000008 /* Multicast Hash Table High */ +#define MAC_HASH_LOW 0x0000000c /* Multicast Hash Table Low */ +#define MAC_MII_ADDR 0x00000010 /* MII Address */ +#define MAC_MII_DATA 0x00000014 /* MII Data */ +#define MAC_FLOW_CTRL 0x00000018 /* Flow Control */ +#define MAC_INT_STATUS 0x00000038 /* interrupt status */ +#define MAC_INT_MASK 0x0000003c /* interrupt mask */ +#define MAC_ADDR0_HIGH 0x00000040 /* MAC Address High */ +#define MAC_ADDR0_LOW 0x00000044 /* MAC Address Low */ +#define MAC_ADDR1_HIGH 0x00000048 /* MAC Address High */ +#define MAC_ADDR1_LOW 0x0000004c /* MAC Address Low */ +#define MAC_WATCHDOG_TO 0x000000dc /* Watchdog Timeout */ +/********************************************************************* + * end + * ******************************************************************/ + + +/* MAC CTRL defines */ +#define MAC_CONTROL_RA 0x80000000 /* Receive All Mode */ +#define MAC_CONTROL_BLE 0x40000000 /* Endian Mode */ + + +/* ****************************************************************** + * 2.Edited By ZengChuanJie + * ******************************************************************/ +// #define MAC_CONTROL_HBD 0x10000000 /* Heartbeat Disable */ +/******************************************************************** + * end + * *******************************************************************/ + + +#define MAC_CONTROL_PS 0x08000000 /* Port Select */ +#define MAC_CONTROL_DRO 0x00800000 /* Disable Receive Own */ +#define MAC_CONTROL_EXT_LOOPBACK 0x00400000 /* Reserved (ext loopback?) */ +#define MAC_CONTROL_OM 0x00200000 /* Loopback Operating Mode */ +#define MAC_CONTROL_F 0x00100000 /* Full Duplex Mode */ + +/* ************************************************************* + * 5.Edited By ZengChuanJie + * ************************************************************/ +#define MAC_CONTROL_PM 0x00000010 /* Pass All Multicast */ +#define MAC_CONTROL_PR 0x00000001 /* Promiscuous Mode */ +#define MAC_CONTROL_IF 0x00000100 /* Inverse Filtering */ +#define MAC_CONTROL_HP 0x00000400 /* Hash/Perfect Filtering Mode */ +/* ************************************************************ + * end + * ************************************************************/ +#define MAC_CONTROL_LCC 0x00001000 /* Late Collision Control */ +#define MAC_CONTROL_DBF 0x00000800 /* Disable Broadcast Frames */ +#define MAC_CONTROL_DRTY 0x00000400 /* Disable Retry */ + + + +/* ******************************************************************* + * 3.Edited by ZengChuanJie + * ******************************************************************/ +#define MAC_CONTROL_ASTP 0x00000080 /* Automatic Pad Stripping */ +/************************ + * end + ***********************/ + + + +#define MAC_CONTROL_BOLMT_10 0x00000000 /* Back Off Limit 10 */ +#define MAC_CONTROL_BOLMT_8 0x00000040 /* Back Off Limit 8 */ +#define MAC_CONTROL_BOLMT_4 0x00000080 /* Back Off Limit 4 */ +#define MAC_CONTROL_BOLMT_1 0x000000c0 /* Back Off Limit 1 */ +#define MAC_CONTROL_DC 0x00000020 /* Deferral Check */ +#define MAC_CONTROL_TE 0x00000008 /* Transmitter Enable */ +#define MAC_CONTROL_RE 0x00000004 /* Receiver Enable */ + + +/************************************* + * 4.Edited by ZengChuanJie + * **********************************/ +#define MAC_CORE_INIT MAC_CONTROL_ASTP +/* end */ + +/* MAC FLOW CTRL defines */ +#define MAC_FLOW_CTRL_PT_MASK 0xffff0000 /* Pause Time Mask */ +#define MAC_FLOW_CTRL_PT_SHIFT 16 + +/* ********************************** + * 6.Edited by ZengCHuanJie + * *********************************/ +//#define MAC_FLOW_CTRL_PASS 0x00000004 /* Pass Control Frames */ +#define MAC_FLOW_CTRL_ENABLE 0x00000006 /* Flow Control Enable */ +/* end */ + + +#define MAC_FLOW_CTRL_PAUSE 0x00000001 /* Flow Control Busy ... */ + +/* MII ADDR defines */ +#define MAC_MII_ADDR_WRITE 0x00000002 /* MII Write */ +#define MAC_MII_ADDR_BUSY 0x00000001 /* MII Busy */ + +/*---------------------------------------------------------------------------- + * DMA BLOCK defines + *---------------------------------------------------------------------------*/ + +/* DMA Bus Mode register defines */ +#define DMA_BUS_MODE_DBO 0x00100000 /* Descriptor Byte Ordering */ +#define DMA_BUS_MODE_BLE 0x00000080 /* Big Endian/Little Endian */ +#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */ +#define DMA_BUS_MODE_PBL_SHIFT 8 +#define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */ +#define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */ +#define DMA_BUS_MODE_BAR_BUS 0x00000002 /* Bar-Bus Arbitration */ +#define DMA_BUS_MODE_SFT_RESET 0x00000001 /* Software Reset */ +#define DMA_BUS_MODE_DEFAULT 0x00000000 + +/* DMA Control register defines */ +#define DMA_CONTROL_SF 0x00200000 /* Store And Forward */ + +/* Transmit Threshold Control */ +enum ttc_control { + DMA_CONTROL_TTC_DEFAULT = 0x00000000, /* Threshold is 32 DWORDS */ + DMA_CONTROL_TTC_64 = 0x00004000, /* Threshold is 64 DWORDS */ + DMA_CONTROL_TTC_128 = 0x00008000, /* Threshold is 128 DWORDS */ + DMA_CONTROL_TTC_256 = 0x0000c000, /* Threshold is 256 DWORDS */ + DMA_CONTROL_TTC_18 = 0x00400000, /* Threshold is 18 DWORDS */ + DMA_CONTROL_TTC_24 = 0x00404000, /* Threshold is 24 DWORDS */ + DMA_CONTROL_TTC_32 = 0x00408000, /* Threshold is 32 DWORDS */ + DMA_CONTROL_TTC_40 = 0x0040c000, /* Threshold is 40 DWORDS */ + DMA_CONTROL_SE = 0x00000008, /* Stop On Empty */ + DMA_CONTROL_OSF = 0x00000004, /* Operate On 2nd Frame */ +}; + +/* STMAC110 DMA Missed Frame Counter register defines */ +#define DMA_MISSED_FRAME_OVE 0x10000000 /* FIFO Overflow Overflow */ +#define DMA_MISSED_FRAME_OVE_CNTR 0x0ffe0000 /* Overflow Frame Counter */ +#define DMA_MISSED_FRAME_OVE_M 0x00010000 /* Missed Frame Overflow */ +#define DMA_MISSED_FRAME_M_CNTR 0x0000ffff /* Missed Frame Couinter */ + +extern const struct stmmac_dma_ops dwmac100_dma_ops; diff -uarN a/drivers/net/xmmac/dwmac1000.h b/drivers/net/xmmac/dwmac1000.h --- a/drivers/net/xmmac/dwmac1000.h 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/dwmac1000.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,208 @@ +/******************************************************************************* + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include +#include "common.h" + +#define GMAC_CONTROL 0x00000000 /* Configuration */ +#define GMAC_FRAME_FILTER 0x00000004 /* Frame Filter */ +#define GMAC_HASH_HIGH 0x00000008 /* Multicast Hash Table High */ +#define GMAC_HASH_LOW 0x0000000c /* Multicast Hash Table Low */ +#define GMAC_MII_ADDR 0x00000010 /* MII Address */ +#define GMAC_MII_DATA 0x00000014 /* MII Data */ +#define GMAC_FLOW_CTRL 0x00000018 /* Flow Control */ +#define GMAC_VLAN_TAG 0x0000001c /* VLAN Tag */ +#define GMAC_VERSION 0x00000020 /* GMAC CORE Version */ +#define GMAC_WAKEUP_FILTER 0x00000028 /* Wake-up Frame Filter */ + +#define GMAC_INT_STATUS 0x00000038 /* interrupt status register */ +enum dwmac1000_irq_status { + time_stamp_irq = 0x0200, + mmc_rx_csum_offload_irq = 0x0080, + mmc_tx_irq = 0x0040, + mmc_rx_irq = 0x0020, + mmc_irq = 0x0010, + pmt_irq = 0x0008, + pcs_ane_irq = 0x0004, + pcs_link_irq = 0x0002, + rgmii_irq = 0x0001, +}; +#define GMAC_INT_MASK 0x0000003c /* interrupt mask register */ + +/* PMT Control and Status */ +#define GMAC_PMT 0x0000002c +enum power_event { + pointer_reset = 0x80000000, + global_unicast = 0x00000200, + wake_up_rx_frame = 0x00000040, + magic_frame = 0x00000020, + wake_up_frame_en = 0x00000004, + magic_pkt_en = 0x00000002, + power_down = 0x00000001, +}; + +/* GMAC HW ADDR regs */ +#define GMAC_ADDR_HIGH(reg) (0x00000040+(reg * 8)) +#define GMAC_ADDR_LOW(reg) (0x00000044+(reg * 8)) +#define GMAC_MAX_UNICAST_ADDRESSES 16 + +#define GMAC_AN_CTRL 0x000000c0 /* AN control */ +#define GMAC_AN_STATUS 0x000000c4 /* AN status */ +#define GMAC_ANE_ADV 0x000000c8 /* Auto-Neg. Advertisement */ +#define GMAC_ANE_LINK 0x000000cc /* Auto-Neg. link partener ability */ +#define GMAC_ANE_EXP 0x000000d0 /* ANE expansion */ +#define GMAC_TBI 0x000000d4 /* TBI extend status */ +#define GMAC_GMII_STATUS 0x000000d8 /* S/R-GMII status */ + +/* GMAC Configuration defines */ +#define GMAC_CONTROL_TC 0x01000000 /* Transmit Conf. in RGMII/SGMII */ +#define GMAC_CONTROL_WD 0x00800000 /* Disable Watchdog on receive */ +#define GMAC_CONTROL_JD 0x00400000 /* Jabber disable */ +#define GMAC_CONTROL_BE 0x00200000 /* Frame Burst Enable */ +#define GMAC_CONTROL_JE 0x00100000 /* Jumbo frame */ +enum inter_frame_gap { + GMAC_CONTROL_IFG_88 = 0x00040000, + GMAC_CONTROL_IFG_80 = 0x00020000, + GMAC_CONTROL_IFG_40 = 0x000e0000, +}; +#define GMAC_CONTROL_DCRS 0x00010000 /* Disable carrier sense during tx */ +#define GMAC_CONTROL_PS 0x00008000 /* Port Select 0:GMI 1:MII */ +#define GMAC_CONTROL_FES 0x00004000 /* Speed 0:10 1:100 */ +#define GMAC_CONTROL_DO 0x00002000 /* Disable Rx Own */ +#define GMAC_CONTROL_LM 0x00001000 /* Loop-back mode */ +#define GMAC_CONTROL_DM 0x00000800 /* Duplex Mode */ +#define GMAC_CONTROL_IPC 0x00000400 /* Checksum Offload */ +#define GMAC_CONTROL_DR 0x00000200 /* Disable Retry */ +#define GMAC_CONTROL_LUD 0x00000100 /* Link up/down */ +#define GMAC_CONTROL_ACS 0x00000080 /* Automatic Pad/FCS Stripping */ +#define GMAC_CONTROL_DC 0x00000010 /* Deferral Check */ +#define GMAC_CONTROL_TE 0x00000008 /* Transmitter Enable */ +#define GMAC_CONTROL_RE 0x00000004 /* Receiver Enable */ + +#define GMAC_CORE_INIT (GMAC_CONTROL_JD | GMAC_CONTROL_PS | GMAC_CONTROL_ACS | \ + GMAC_CONTROL_JE | GMAC_CONTROL_BE) + +/* GMAC Frame Filter defines */ +#define GMAC_FRAME_FILTER_PR 0x00000001 /* Promiscuous Mode */ +#define GMAC_FRAME_FILTER_HUC 0x00000002 /* Hash Unicast */ +#define GMAC_FRAME_FILTER_HMC 0x00000004 /* Hash Multicast */ +#define GMAC_FRAME_FILTER_DAIF 0x00000008 /* DA Inverse Filtering */ +#define GMAC_FRAME_FILTER_PM 0x00000010 /* Pass all multicast */ +#define GMAC_FRAME_FILTER_DBF 0x00000020 /* Disable Broadcast frames */ +#define GMAC_FRAME_FILTER_SAIF 0x00000100 /* Inverse Filtering */ +#define GMAC_FRAME_FILTER_SAF 0x00000200 /* Source Address Filter */ +#define GMAC_FRAME_FILTER_HPF 0x00000400 /* Hash or perfect Filter */ +#define GMAC_FRAME_FILTER_RA 0x80000000 /* Receive all mode */ +/* GMII ADDR defines */ +#define GMAC_MII_ADDR_WRITE 0x00000002 /* MII Write */ +#define GMAC_MII_ADDR_BUSY 0x00000001 /* MII Busy */ +/* GMAC FLOW CTRL defines */ +#define GMAC_FLOW_CTRL_PT_MASK 0xffff0000 /* Pause Time Mask */ +#define GMAC_FLOW_CTRL_PT_SHIFT 16 +#define GMAC_FLOW_CTRL_RFE 0x00000004 /* Rx Flow Control Enable */ +#define GMAC_FLOW_CTRL_TFE 0x00000002 /* Tx Flow Control Enable */ +#define GMAC_FLOW_CTRL_FCB_BPA 0x00000001 /* Flow Control Busy ... */ + +/*--- DMA BLOCK defines ---*/ +/* DMA Bus Mode register defines */ +#define DMA_BUS_MODE_SFT_RESET 0x00000001 /* Software Reset */ +#define DMA_BUS_MODE_DA 0x00000002 /* Arbitration scheme */ +#define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */ +#define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */ +/* Programmable burst length (passed thorugh platform)*/ +#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */ +#define DMA_BUS_MODE_PBL_SHIFT 8 + +enum rx_tx_priority_ratio { + double_ratio = 0x00004000, /*2:1 */ + triple_ratio = 0x00008000, /*3:1 */ + quadruple_ratio = 0x0000c000, /*4:1 */ +}; + +#define DMA_BUS_MODE_FB 0x00010000 /* Fixed burst */ +#define DMA_BUS_MODE_RPBL_MASK 0x003e0000 /* Rx-Programmable Burst Len */ +#define DMA_BUS_MODE_RPBL_SHIFT 17 +#define DMA_BUS_MODE_USP 0x00800000 +#define DMA_BUS_MODE_4PBL 0x01000000 +#define DMA_BUS_MODE_AAL 0x02000000 + +/* DMA CRS Control and Status Register Mapping */ +#define DMA_HOST_TX_DESC 0x00001048 /* Current Host Tx descriptor */ +#define DMA_HOST_RX_DESC 0x0000104c /* Current Host Rx descriptor */ +/* DMA Bus Mode register defines */ +#define DMA_BUS_PR_RATIO_MASK 0x0000c000 /* Rx/Tx priority ratio */ +#define DMA_BUS_PR_RATIO_SHIFT 14 +#define DMA_BUS_FB 0x00010000 /* Fixed Burst */ + +/* DMA operation mode defines (start/stop tx/rx are placed in common header)*/ +#define DMA_CONTROL_DT 0x04000000 /* Disable Drop TCP/IP csum error */ +#define DMA_CONTROL_RSF 0x02000000 /* Receive Store and Forward */ +#define DMA_CONTROL_DFF 0x01000000 /* Disaable flushing */ +/* Threshold for Activating the FC */ +enum rfa { + act_full_minus_1 = 0x00800000, + act_full_minus_2 = 0x00800200, + act_full_minus_3 = 0x00800400, + act_full_minus_4 = 0x00800600, +}; +/* Threshold for Deactivating the FC */ +enum rfd { + deac_full_minus_1 = 0x00400000, + deac_full_minus_2 = 0x00400800, + deac_full_minus_3 = 0x00401000, + deac_full_minus_4 = 0x00401800, +}; +#define DMA_CONTROL_TSF 0x00200000 /* Transmit Store and Forward */ + +enum ttc_control { + DMA_CONTROL_TTC_64 = 0x00000000, + DMA_CONTROL_TTC_128 = 0x00004000, + DMA_CONTROL_TTC_192 = 0x00008000, + DMA_CONTROL_TTC_256 = 0x0000c000, + DMA_CONTROL_TTC_40 = 0x00010000, + DMA_CONTROL_TTC_32 = 0x00014000, + DMA_CONTROL_TTC_24 = 0x00018000, + DMA_CONTROL_TTC_16 = 0x0001c000, +}; +#define DMA_CONTROL_TC_TX_MASK 0xfffe3fff + +#define DMA_CONTROL_EFC 0x00000100 +#define DMA_CONTROL_FEF 0x00000080 +#define DMA_CONTROL_FUF 0x00000040 + +enum rtc_control { + DMA_CONTROL_RTC_64 = 0x00000000, + DMA_CONTROL_RTC_32 = 0x00000008, + DMA_CONTROL_RTC_96 = 0x00000010, + DMA_CONTROL_RTC_128 = 0x00000018, +}; +#define DMA_CONTROL_TC_RX_MASK 0xffffffe7 + +#define DMA_CONTROL_OSF 0x00000004 /* Operate on second frame */ + +/* MMC registers offset */ +#define GMAC_MMC_CTRL 0x100 +#define GMAC_MMC_RX_INTR 0x104 +#define GMAC_MMC_TX_INTR 0x108 +#define GMAC_MMC_RX_CSUM_OFFLOAD 0x208 + +extern const struct stmmac_dma_ops dwmac1000_dma_ops; diff -uarN a/drivers/net/xmmac/dwmac1000_core.c b/drivers/net/xmmac/dwmac1000_core.c --- a/drivers/net/xmmac/dwmac1000_core.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/dwmac1000_core.c 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,250 @@ +/******************************************************************************* + This is the driver for the GMAC on-chip Ethernet controller for ST SoCs. + DWC Ether MAC 10/100/1000 Universal version 3.41a has been used for + developing this code. + + This only implements the mac core functions for this chip. + + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include +#include +#include "dwmac1000.h" + +static void dwmac1000_core_init(void __iomem *ioaddr) +{ + u32 value = readl(ioaddr + GMAC_CONTROL); + value |= GMAC_CORE_INIT; + writel(value, ioaddr + GMAC_CONTROL); + + /* STBus Bridge Configuration */ + /*writel(0xc5608, ioaddr + 0x00007000);*/ + + /* Freeze MMC counters */ + writel(0x8, ioaddr + GMAC_MMC_CTRL); + /* Mask GMAC interrupts */ + writel(0x207, ioaddr + GMAC_INT_MASK); + +#ifdef STMMAC_VLAN_TAG_USED + /* Tag detection without filtering */ + writel(0x0, ioaddr + GMAC_VLAN_TAG); +#endif +} + +static int dwmac1000_rx_coe_supported(void __iomem *ioaddr) +{ + u32 value = readl(ioaddr + GMAC_CONTROL); + + value |= GMAC_CONTROL_IPC; + writel(value, ioaddr + GMAC_CONTROL); + + value = readl(ioaddr + GMAC_CONTROL); + + return !!(value & GMAC_CONTROL_IPC); +} + +static void dwmac1000_dump_regs(void __iomem *ioaddr) +{ + int i; + pr_info("\tDWMAC1000 regs (base addr = 0x%p)\n", ioaddr); + + for (i = 0; i < 55; i++) { + int offset = i * 4; + pr_info("\tReg No. %d (offset 0x%x): 0x%08x\n", i, + offset, readl(ioaddr + offset)); + } +} + +static void dwmac1000_set_umac_addr(void __iomem *ioaddr, unsigned char *addr, + unsigned int reg_n) +{ + stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n), + GMAC_ADDR_LOW(reg_n)); +} + +static void dwmac1000_get_umac_addr(void __iomem *ioaddr, unsigned char *addr, + unsigned int reg_n) +{ + stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n), + GMAC_ADDR_LOW(reg_n)); +} + +static void dwmac1000_set_filter(struct net_device *dev) +{ + void __iomem *ioaddr = (void __iomem *) dev->base_addr; + unsigned int value = 0; + + CHIP_DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n", + __func__, netdev_mc_count(dev), netdev_uc_count(dev)); + + if (dev->flags & IFF_PROMISC) + value = GMAC_FRAME_FILTER_PR; + else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE) + || (dev->flags & IFF_ALLMULTI)) { + value = GMAC_FRAME_FILTER_PM; /* pass all multi */ + writel(0xffffffff, ioaddr + GMAC_HASH_HIGH); + writel(0xffffffff, ioaddr + GMAC_HASH_LOW); + } else if (!netdev_mc_empty(dev)) { + u32 mc_filter[2]; + struct netdev_hw_addr *ha; + + /* Hash filter for multicast */ + value = GMAC_FRAME_FILTER_HMC; + + memset(mc_filter, 0, sizeof(mc_filter)); + netdev_for_each_mc_addr(ha, dev) { + /* The upper 6 bits of the calculated CRC are used to + index the contens of the hash table */ + int bit_nr = + bitrev32(~crc32_le(~0, ha->addr, 6)) >> 26; + /* The most significant bit determines the register to + * use (H/L) while the other 5 bits determine the bit + * within the register. */ + mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); + } + writel(mc_filter[0], ioaddr + GMAC_HASH_LOW); + writel(mc_filter[1], ioaddr + GMAC_HASH_HIGH); + } + + /* Handle multiple unicast addresses (perfect filtering)*/ + if (netdev_uc_count(dev) > GMAC_MAX_UNICAST_ADDRESSES) + /* Switch to promiscuous mode is more than 16 addrs + are required */ + value |= GMAC_FRAME_FILTER_PR; + else { + int reg = 1; + struct netdev_hw_addr *ha; + + netdev_for_each_uc_addr(ha, dev) { + dwmac1000_set_umac_addr(ioaddr, ha->addr, reg); + reg++; + } + } + +#ifdef FRAME_FILTER_DEBUG + /* Enable Receive all mode (to debug filtering_fail errors) */ + value |= GMAC_FRAME_FILTER_RA; +#endif + writel(value, ioaddr + GMAC_FRAME_FILTER); + + CHIP_DBG(KERN_INFO "\tFrame Filter reg: 0x%08x\n\tHash regs: " + "HI 0x%08x, LO 0x%08x\n", readl(ioaddr + GMAC_FRAME_FILTER), + readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW)); +} + +static void dwmac1000_flow_ctrl(void __iomem *ioaddr, unsigned int duplex, + unsigned int fc, unsigned int pause_time) +{ + unsigned int flow = 0; + + CHIP_DBG(KERN_DEBUG "GMAC Flow-Control:\n"); + if (fc & FLOW_RX) { + CHIP_DBG(KERN_DEBUG "\tReceive Flow-Control ON\n"); + flow |= GMAC_FLOW_CTRL_RFE; + } + if (fc & FLOW_TX) { + CHIP_DBG(KERN_DEBUG "\tTransmit Flow-Control ON\n"); + flow |= GMAC_FLOW_CTRL_TFE; + } + + if (duplex) { + CHIP_DBG(KERN_DEBUG "\tduplex mode: PAUSE %d\n", pause_time); + flow |= (pause_time << GMAC_FLOW_CTRL_PT_SHIFT); + } + + writel(flow, ioaddr + GMAC_FLOW_CTRL); +} + +static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode) +{ + unsigned int pmt = 0; + + if (mode & WAKE_MAGIC) { + CHIP_DBG(KERN_DEBUG "GMAC: WOL Magic frame\n"); + pmt |= power_down | magic_pkt_en; + } + if (mode & WAKE_UCAST) { + CHIP_DBG(KERN_DEBUG "GMAC: WOL on global unicast\n"); + pmt |= global_unicast; + } + + writel(pmt, ioaddr + GMAC_PMT); +} + + +static void dwmac1000_irq_status(void __iomem *ioaddr) +{ + u32 intr_status = readl(ioaddr + GMAC_INT_STATUS); + + /* Not used events (e.g. MMC interrupts) are not handled. */ + if ((intr_status & mmc_tx_irq)) + CHIP_DBG(KERN_DEBUG "GMAC: MMC tx interrupt: 0x%08x\n", + readl(ioaddr + GMAC_MMC_TX_INTR)); + if (unlikely(intr_status & mmc_rx_irq)) + CHIP_DBG(KERN_DEBUG "GMAC: MMC rx interrupt: 0x%08x\n", + readl(ioaddr + GMAC_MMC_RX_INTR)); + if (unlikely(intr_status & mmc_rx_csum_offload_irq)) + CHIP_DBG(KERN_DEBUG "GMAC: MMC rx csum offload: 0x%08x\n", + readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD)); + if (unlikely(intr_status & pmt_irq)) { + CHIP_DBG(KERN_DEBUG "GMAC: received Magic frame\n"); + /* clear the PMT bits 5 and 6 by reading the PMT + * status register. */ + readl(ioaddr + GMAC_PMT); + } +} + +static const struct stmmac_ops dwmac1000_ops = { + .core_init = dwmac1000_core_init, + .rx_coe = dwmac1000_rx_coe_supported, + .dump_regs = dwmac1000_dump_regs, + .host_irq_status = dwmac1000_irq_status, + .set_filter = dwmac1000_set_filter, + .flow_ctrl = dwmac1000_flow_ctrl, + .pmt = dwmac1000_pmt, + .set_umac_addr = dwmac1000_set_umac_addr, + .get_umac_addr = dwmac1000_get_umac_addr, +}; + +struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr) +{ + struct mac_device_info *mac; + u32 uid = readl(ioaddr + GMAC_VERSION); + + pr_info("\tDWMAC1000 - user ID: 0x%x, Synopsys ID: 0x%x\n", + ((uid & 0x0000ff00) >> 8), (uid & 0x000000ff)); + + mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL); + if (!mac) + return NULL; + + mac->mac = &dwmac1000_ops; + mac->dma = &dwmac1000_dma_ops; + + mac->link.port = GMAC_CONTROL_PS; + mac->link.duplex = GMAC_CONTROL_DM; + mac->link.speed = GMAC_CONTROL_FES; + mac->mii.addr = GMAC_MII_ADDR; + mac->mii.data = GMAC_MII_DATA; + + return mac; +} diff -uarN a/drivers/net/xmmac/dwmac1000_dma.c b/drivers/net/xmmac/dwmac1000_dma.c --- a/drivers/net/xmmac/dwmac1000_dma.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/dwmac1000_dma.c 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,154 @@ +/******************************************************************************* + This is the driver for the GMAC on-chip Ethernet controller for ST SoCs. + DWC Ether MAC 10/100/1000 Universal version 3.41a has been used for + developing this code. + + This contains the functions to handle the dma. + + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include "dwmac1000.h" +#include "dwmac_dma.h" + +static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, u32 dma_tx, + u32 dma_rx) +{ + u32 value = readl(ioaddr + DMA_BUS_MODE); + int limit; + + /* DMA SW reset */ + value |= DMA_BUS_MODE_SFT_RESET; + writel(value, ioaddr + DMA_BUS_MODE); + limit = 15000; + while (limit--) { + if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET)) + break; + } + if (limit < 0) + return -EBUSY; + + value = /* DMA_BUS_MODE_FB | */ DMA_BUS_MODE_4PBL | + ((pbl << DMA_BUS_MODE_PBL_SHIFT) | + (pbl << DMA_BUS_MODE_RPBL_SHIFT)); + +#ifdef CONFIG_STMMAC_DA + value |= DMA_BUS_MODE_DA; /* Rx has priority over tx */ +#endif + writel(value, ioaddr + DMA_BUS_MODE); + + /* Mask interrupts by writing to CSR7 */ + writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA); + + /* The base address of the RX/TX descriptor lists must be written into + * DMA CSR3 and CSR4, respectively. */ + writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR); + writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR); + + return 0; +} + +static void dwmac1000_dma_operation_mode(void __iomem *ioaddr, int txmode, + int rxmode) +{ + u32 csr6 = readl(ioaddr + DMA_CONTROL); + + if (txmode == SF_DMA_MODE) { + CHIP_DBG(KERN_DEBUG "GMAC: enable TX store and forward mode\n"); + /* Transmit COE type 2 cannot be done in cut-through mode. */ + csr6 |= DMA_CONTROL_TSF; + /* Operating on second frame increase the performance + * especially when transmit store-and-forward is used.*/ + csr6 |= DMA_CONTROL_OSF; + } else { + CHIP_DBG(KERN_DEBUG "GMAC: disabling TX store and forward mode" + " (threshold = %d)\n", txmode); + csr6 &= ~DMA_CONTROL_TSF; + csr6 &= DMA_CONTROL_TC_TX_MASK; + /* Set the transmit threshold */ + if (txmode <= 32) + csr6 |= DMA_CONTROL_TTC_32; + else if (txmode <= 64) + csr6 |= DMA_CONTROL_TTC_64; + else if (txmode <= 128) + csr6 |= DMA_CONTROL_TTC_128; + else if (txmode <= 192) + csr6 |= DMA_CONTROL_TTC_192; + else + csr6 |= DMA_CONTROL_TTC_256; + } + + if (rxmode == SF_DMA_MODE) { + CHIP_DBG(KERN_DEBUG "GMAC: enable RX store and forward mode\n"); + csr6 |= DMA_CONTROL_RSF; + } else { + CHIP_DBG(KERN_DEBUG "GMAC: disabling RX store and forward mode" + " (threshold = %d)\n", rxmode); + csr6 &= ~DMA_CONTROL_RSF; + csr6 &= DMA_CONTROL_TC_RX_MASK; + if (rxmode <= 32) + csr6 |= DMA_CONTROL_RTC_32; + else if (rxmode <= 64) + csr6 |= DMA_CONTROL_RTC_64; + else if (rxmode <= 96) + csr6 |= DMA_CONTROL_RTC_96; + else + csr6 |= DMA_CONTROL_RTC_128; + } + + writel(csr6, ioaddr + DMA_CONTROL); +} + +/* Not yet implemented --- no RMON module */ +static void dwmac1000_dma_diagnostic_fr(void *data, + struct stmmac_extra_stats *x, void __iomem *ioaddr) +{ + return; +} + +static void dwmac1000_dump_dma_regs(void __iomem *ioaddr) +{ + int i; + pr_info(" DMA registers\n"); + for (i = 0; i < 22; i++) { + if ((i < 9) || (i > 17)) { + int offset = i * 4; + pr_err("\t Reg No. %d (offset 0x%x): 0x%08x\n", i, + (DMA_BUS_MODE + offset), + readl(ioaddr + DMA_BUS_MODE + offset)); + } + } +} + +const struct stmmac_dma_ops dwmac1000_dma_ops = { + .init = dwmac1000_dma_init, + .dump_regs = dwmac1000_dump_dma_regs, + .dma_mode = dwmac1000_dma_operation_mode, + .dma_diagnostic_fr = dwmac1000_dma_diagnostic_fr, + .enable_dma_transmission = dwmac_enable_dma_transmission, + .enable_dma_irq = dwmac_enable_dma_irq, + .disable_dma_irq = dwmac_disable_dma_irq, + .start_tx = dwmac_dma_start_tx, + .stop_tx = dwmac_dma_stop_tx, + .start_rx = dwmac_dma_start_rx, + .stop_rx = dwmac_dma_stop_rx, + .dma_interrupt = dwmac_dma_interrupt, +}; diff -uarN a/drivers/net/xmmac/dwmac100_core.c b/drivers/net/xmmac/dwmac100_core.c --- a/drivers/net/xmmac/dwmac100_core.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/dwmac100_core.c 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,306 @@ +/******************************************************************************* + This is the driver for the MAC 10/100 on-chip Ethernet controller + currently tested on all the ST boards based on STb7109 and stx7200 SoCs. + + DWC Ether MAC 10/100 Universal version 4.0 has been used for developing + this code. + + This only implements the mac core functions for this chip. + + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + +Author: Giuseppe Cavallaro + *******************************************************************************/ + +#include +#include "dwmac100.h" + +static void dwmac100_core_init(void __iomem *ioaddr) +{ + u32 value = readl(ioaddr + MAC_CONTROL); + + writel((value | MAC_CORE_INIT), ioaddr + MAC_CONTROL); + + /********************************************** + * Added By ZengChuanJie + * *******************************************/ + + /* Flow Control */ + /* 1.Pause Time 0x200 */ + //value = MAC_FLOW_CTRL_PAUSETIME; + /* 2.Enable Zero-Quanta Pause */ + /* 3. Pause Low Threshold */ +// value |= MAC_FLOW_CTRL_PLT28; + /* 4. Unicase Pause Frame Detect */ +// value |= MAC_FLOW_CTRL_UP; + /* 5. Enable Receive and Transmit Flow Control */ +// value |= (MAC_FLOW_CTRL_RFE|MAC_FLOW_CTRL_TFE); +// writel(value, ioaddr+MAC_FLOW_CTRL); + + /* end */ +} + +static int dwmac100_rx_coe_supported(void __iomem *ioaddr) +{ + return 0; +} + +static void dwmac100_dump_mac_regs(void __iomem *ioaddr) +{ + pr_info("\t----------------------------------------------\n" + "\t DWMAC 100 CSR (base addr = 0x%p)\n" + "\t----------------------------------------------\n", + ioaddr); + /* ******************************************************** + * Edited By ZengChuanJie + * *******************************************************/ + pr_info("\tcontrol reg (offset 0x%x): 0x%08x\n", MAC_CONTROL, + readl(ioaddr + MAC_CONTROL)); + pr_info("\tframe filter (offset 0x%x): 0x%08x\n ", MAC_FRAME_FLT, + readl(ioaddr + MAC_FRAME_FLT)); + pr_info("\thash high (offset 0x%x): 0x%08x\n", MAC_HASH_HIGH, + readl(ioaddr + MAC_HASH_HIGH)); + pr_info("\thash low (offset 0x%x): 0x%08x\n", + MAC_HASH_LOW, readl(ioaddr + MAC_HASH_LOW)); + pr_info("\tmii addr (offset 0x%x): 0x%08x\n", + MAC_MII_ADDR, readl(ioaddr + MAC_MII_ADDR)); + pr_info("\tmii data (offset 0x%x): 0x%08x\n", + MAC_MII_DATA, readl(ioaddr + MAC_MII_DATA)); + pr_info("\tflow control (offset 0x%x): 0x%08x\n", MAC_FLOW_CTRL, + readl(ioaddr + MAC_FLOW_CTRL)); + pr_info("\tint status (offset 0x%x): 0x%08x\n", MAC_INT_STATUS, + readl(ioaddr + MAC_INT_STATUS)); + + /* end */ + +} + +static void dwmac100_irq_status(void __iomem *ioaddr) +{ + return; +} + +#if 0 +void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6], + unsigned int high, unsigned int low) +{ + unsigned long data; + + data = (addr[5] << 8) | addr[4]; + writel(data, ioaddr + high); + data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; + writel(data, ioaddr + low); +} +#endif + +#if 0 +void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, + unsigned int high, unsigned int low) +{ + unsigned int hi_addr, lo_addr; + + /* Read the MAC address from the hardware */ + hi_addr = readl(ioaddr + high); + lo_addr = readl(ioaddr + low); + + /* Extract the MAC address from the high and low words */ + addr[0] = lo_addr & 0xff; + addr[1] = (lo_addr >> 8) & 0xff; + addr[2] = (lo_addr >> 16) & 0xff; + addr[3] = (lo_addr >> 24) & 0xff; + addr[4] = hi_addr & 0xff; + addr[5] = (hi_addr >> 8) & 0xff; +} +#endif + + +static void dwmac100_set_umac_addr(void __iomem *ioaddr, unsigned char *addr, + unsigned int reg_n) +{ + /* ********************************************************** + * Edited by ZengChuanJie + * **********************************************************/ + stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR0_HIGH, MAC_ADDR0_LOW); + /* end */ +} + +static void dwmac100_get_umac_addr(void __iomem *ioaddr, unsigned char *addr, + unsigned int reg_n) +{ + /* ********************************************************** + * Edited by ZengChuanJie + * **********************************************************/ + stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR0_HIGH, MAC_ADDR0_LOW); + /* end */ +} + +static void dwmac100_set_filter(struct net_device *dev) +{ + void __iomem *ioaddr = (void __iomem *) dev->base_addr; + u32 value = readl(ioaddr + MAC_FRAME_FLT); + + if (dev->flags & IFF_PROMISC) { + /* 通过所有的帧,不需要过滤 */ + value |= MAC_CONTROL_PR; + value &= ~(MAC_CONTROL_PM | MAC_CONTROL_IF | + MAC_CONTROL_HP); + } else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE) + || (dev->flags & IFF_ALLMULTI)) { + /* 超过可用容纳的多播帧 */ + value |= MAC_CONTROL_PM; + value &= ~(MAC_CONTROL_PR | MAC_CONTROL_IF); + writel(0xffffffff, ioaddr + MAC_HASH_HIGH); + writel(0xffffffff, ioaddr + MAC_HASH_LOW); + } else if (netdev_mc_empty(dev)) { /* no multicast */ + /* 没有多播帧,这个函数只会通过set_multilist_addr提供接口,所以不会进入这个分支 */ + value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR + | MAC_CONTROL_HP); + } else { + u32 mc_filter[2]; + struct netdev_hw_addr *ha; + + /* Perfect filter mode for physical address and Hash + filter for multicast */ + value |= MAC_CONTROL_HP ; + value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | + MAC_CONTROL_IF); + //value |= 0x10; + value |= 0x4; + + //int i; + //for (i=0; i<6; i++) + // printk(KERN_EMERG"%02x ", ha->addr[i]); + //printk(KERN_EMERG"set_multilist_addr\n"); + + memset(mc_filter, 0, sizeof(mc_filter)); + netdev_for_each_mc_addr(ha, dev) { + /* The upper 6 bits of the calculated CRC are used to + * index the contens of the hash table */ + // for (i=0; i<6; i++) + // printk(KERN_EMERG"%02x ", ha->addr[i]); + // printk("\n"); +#if 1 + + int bit_nr = + ether_crc(ETH_ALEN, ha->addr) >> 26; + + //printk("bit_nr:%x\n", bit_nr); + bit_nr = ~bit_nr; + //printk("bit_nr:%x\n", bit_nr); + bit_nr &= 0x3f; +#endif +#if 0 + + /* crc32 */ + unsigned int bit_nr = crc32_le(~0, ha->addr, ETH_ALEN); + + printk("bit_nr:%x\n", bit_nr); + bit_nr = bitrev32(bit_nr); + printk("bit_nr:%x\n", bit_nr); + /* get 31bit-26bit */ + bit_nr = bit_nr>>26; + printk("bit_nr:%x\n", bit_nr); + + /* ~ */ + bit_nr = ~bit_nr; + printk("bit_nr:%x\n", bit_nr); + + /* lowest 6 bits */ + bit_nr = bit_nr &0x3f; + printk("bit_nr:%x\n", bit_nr); +#endif + + /* The most significant bit determines the register to + * use (H/L) while the other 5 bits determine the bit + * within the register. */ + mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); + /* 计算出高低HASH 过滤寄存器的值 */ + } + //mc_filter[1] = 0xffffffff; /* OK */ + //mc_filter[1] = 0xffff; + //mc_filter[1] = 0xff000000; + //mc_filter[1] = 0x00f00000; /* OK */ + //mc_filter[1] = 0x00c00000; /* OK */ + //mc_filter[1] = 0x00800000; /* OK */ + writel(mc_filter[0], ioaddr + MAC_HASH_LOW); + writel(mc_filter[1], ioaddr + MAC_HASH_HIGH); + //printk(KERN_EMERG"low:%x\n", mc_filter[0]); + //printk(KERN_EMERG"high:%x\n", mc_filter[1]); + } + + writel(value, ioaddr + MAC_FRAME_FLT); + + CHIP_DBG(KERN_INFO "%s: frame fileter reg: 0x%08x Hash regs: " + "HI 0x%08x, LO 0x%08x\n", + __func__, readl(ioaddr + MAC_FRAME_FLT), + readl(ioaddr + MAC_HASH_HIGH), readl(ioaddr + MAC_HASH_LOW)); +} + +static void dwmac100_flow_ctrl(void __iomem *ioaddr, unsigned int duplex, + unsigned int fc, unsigned int pause_time) +{ + unsigned int flow = MAC_FLOW_CTRL_ENABLE; + + if (duplex) + flow |= (pause_time << MAC_FLOW_CTRL_PT_SHIFT); + //printk("flow:%x\n", flow); + writel(flow, ioaddr + MAC_FLOW_CTRL); +} + +/* No PMT module supported for this Ethernet Controller. + * Tested on ST platforms only. + */ +static void dwmac100_pmt(void __iomem *ioaddr, unsigned long mode) +{ + return; +} + +static const struct stmmac_ops dwmac100_ops = { + .core_init = dwmac100_core_init, + .rx_coe = dwmac100_rx_coe_supported, + .dump_regs = dwmac100_dump_mac_regs, + .host_irq_status = dwmac100_irq_status, + .set_filter = dwmac100_set_filter, + .flow_ctrl = dwmac100_flow_ctrl, + .pmt = dwmac100_pmt, + .set_umac_addr = dwmac100_set_umac_addr, + .get_umac_addr = dwmac100_get_umac_addr, +}; + +struct mac_device_info *dwmac100_setup(void __iomem *ioaddr) +{ + struct mac_device_info *mac; + + mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL); + if (!mac) + return NULL; + + //pr_info("\tDWMAC100\n"); + + mac->mac = &dwmac100_ops; + mac->dma = &dwmac100_dma_ops; + + mac->link.port = MAC_CONTROL_PS; + mac->link.duplex = MAC_CONTROL_F; + mac->link.speed = 0; + mac->mii.addr = MAC_MII_ADDR; + mac->mii.data = MAC_MII_DATA; + + return mac; +} diff -uarN a/drivers/net/xmmac/dwmac100_dma.c b/drivers/net/xmmac/dwmac100_dma.c --- a/drivers/net/xmmac/dwmac100_dma.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/dwmac100_dma.c 2018-12-26 09:52:58.000000000 +0300 @@ -0,0 +1,145 @@ +/******************************************************************************* + This is the driver for the MAC 10/100 on-chip Ethernet controller + currently tested on all the ST boards based on STb7109 and stx7200 SoCs. + + DWC Ether MAC 10/100 Universal version 4.0 has been used for developing + this code. + + This contains the functions to handle the dma. + + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include "dwmac100.h" +#include "dwmac_dma.h" + +static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, u32 dma_tx, + u32 dma_rx) +{ + u32 value = readl(ioaddr + DMA_BUS_MODE); + int limit; + + /* DMA SW reset */ + value |= DMA_BUS_MODE_SFT_RESET; + writel(value, ioaddr + DMA_BUS_MODE); + limit = 15000; + while (limit--) { + if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET)) + break; + } + if (limit < 0) + return -EBUSY; + + /* Enable Application Access by writing to DMA CSR0 */ + writel(DMA_BUS_MODE_DEFAULT | (pbl << DMA_BUS_MODE_PBL_SHIFT), + ioaddr + DMA_BUS_MODE); + + /* Mask interrupts by writing to CSR7 */ + writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA); + + /* The base address of the RX/TX descriptor lists must be written into + * DMA CSR3 and CSR4, respectively. */ + writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR); + writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR); + + return 0; +} + +/* Store and Forward capability is not used at all.. + * The transmit threshold can be programmed by + * setting the TTC bits in the DMA control register.*/ +static void dwmac100_dma_operation_mode(void __iomem *ioaddr, int txmode, + int rxmode) +{ + u32 csr6 = readl(ioaddr + DMA_CONTROL); + + +#if 0 + if (txmode <= 64) + csr6 |= 0; + else + /* > 64 */ + csr6 |= 3<<14; +#endif + csr6 |= 1<<21; + + writel(csr6, ioaddr + DMA_CONTROL); +} + +static void dwmac100_dump_dma_regs(void __iomem *ioaddr) +{ + int i; + + CHIP_DBG(KERN_DEBUG "DWMAC 100 DMA CSR\n"); + for (i = 0; i < 9; i++) + pr_debug("\t CSR%d (offset 0x%x): 0x%08x\n", i, + (DMA_BUS_MODE + i * 4), + readl(ioaddr + DMA_BUS_MODE + i * 4)); + CHIP_DBG(KERN_DEBUG "\t CSR20 (offset 0x%x): 0x%08x\n", + DMA_CUR_TX_BUF_ADDR, readl(ioaddr + DMA_CUR_TX_BUF_ADDR)); + CHIP_DBG(KERN_DEBUG "\t CSR21 (offset 0x%x): 0x%08x\n", + DMA_CUR_RX_BUF_ADDR, readl(ioaddr + DMA_CUR_RX_BUF_ADDR)); +} + +/* DMA controller has two counters to track the number of + * the receive missed frames. */ +static void dwmac100_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x, + void __iomem *ioaddr) +{ + struct net_device_stats *stats = (struct net_device_stats *)data; + u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR); + + if (unlikely(csr8)) { + if (csr8 & DMA_MISSED_FRAME_OVE) { + stats->rx_over_errors += 0x800; + x->rx_overflow_cntr += 0x800; + } else { + unsigned int ove_cntr; + ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17); + stats->rx_over_errors += ove_cntr; + x->rx_overflow_cntr += ove_cntr; + } + + if (csr8 & DMA_MISSED_FRAME_OVE_M) { + stats->rx_missed_errors += 0xffff; + x->rx_missed_cntr += 0xffff; + } else { + unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR); + stats->rx_missed_errors += miss_f; + x->rx_missed_cntr += miss_f; + } + } +} + +const struct stmmac_dma_ops dwmac100_dma_ops = { + .init = dwmac100_dma_init, + .dump_regs = dwmac100_dump_dma_regs, + .dma_mode = dwmac100_dma_operation_mode, + .dma_diagnostic_fr = dwmac100_dma_diagnostic_fr, + .enable_dma_transmission = dwmac_enable_dma_transmission, + .enable_dma_irq = dwmac_enable_dma_irq, + .disable_dma_irq = dwmac_disable_dma_irq, + .start_tx = dwmac_dma_start_tx, + .stop_tx = dwmac_dma_stop_tx, + .start_rx = dwmac_dma_start_rx, + .stop_rx = dwmac_dma_stop_rx, + .dma_interrupt = dwmac_dma_interrupt, +}; diff -uarN a/drivers/net/xmmac/dwmac_dma.h b/drivers/net/xmmac/dwmac_dma.h --- a/drivers/net/xmmac/dwmac_dma.h 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/dwmac_dma.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,108 @@ +/******************************************************************************* + DWMAC DMA Header file. + + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +/* DMA CRS Control and Status Register Mapping */ +#define DMA_BUS_MODE 0x00001000 /* Bus Mode */ +#define DMA_XMT_POLL_DEMAND 0x00001004 /* Transmit Poll Demand */ +#define DMA_RCV_POLL_DEMAND 0x00001008 /* Received Poll Demand */ +#define DMA_RCV_BASE_ADDR 0x0000100c /* Receive List Base */ +#define DMA_TX_BASE_ADDR 0x00001010 /* Transmit List Base */ +#define DMA_STATUS 0x00001014 /* Status Register */ +#define DMA_CONTROL 0x00001018 /* Ctrl (Operational Mode) */ +#define DMA_INTR_ENA 0x0000101c /* Interrupt Enable */ +#define DMA_MISSED_FRAME_CTR 0x00001020 /* Missed Frame Counter */ +#define DMA_CUR_TX_BUF_ADDR 0x00001050 /* Current Host Tx Buffer */ +#define DMA_CUR_RX_BUF_ADDR 0x00001054 /* Current Host Rx Buffer */ + +/* DMA Control register defines */ +#define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */ +#define DMA_CONTROL_SR 0x00000002 /* Start/Stop Receive */ + +/* DMA Normal interrupt */ +#define DMA_INTR_ENA_NIE 0x00010000 /* Normal Summary */ +#define DMA_INTR_ENA_TIE 0x00000001 /* Transmit Interrupt */ +#define DMA_INTR_ENA_TUE 0x00000004 /* Transmit Buffer Unavailable */ +#define DMA_INTR_ENA_RIE 0x00000040 /* Receive Interrupt */ +#define DMA_INTR_ENA_ERE 0x00004000 /* Early Receive */ + +#define DMA_INTR_NORMAL (DMA_INTR_ENA_NIE | DMA_INTR_ENA_RIE | \ + DMA_INTR_ENA_TIE) + +/* DMA Abnormal interrupt */ +#define DMA_INTR_ENA_AIE 0x00008000 /* Abnormal Summary */ +#define DMA_INTR_ENA_FBE 0x00002000 /* Fatal Bus Error */ +#define DMA_INTR_ENA_ETE 0x00000400 /* Early Transmit */ +#define DMA_INTR_ENA_RWE 0x00000200 /* Receive Watchdog */ +#define DMA_INTR_ENA_RSE 0x00000100 /* Receive Stopped */ +#define DMA_INTR_ENA_RUE 0x00000080 /* Receive Buffer Unavailable */ +#define DMA_INTR_ENA_UNE 0x00000020 /* Tx Underflow */ +#define DMA_INTR_ENA_OVE 0x00000010 /* Receive Overflow */ +#define DMA_INTR_ENA_TJE 0x00000008 /* Transmit Jabber */ +#define DMA_INTR_ENA_TSE 0x00000002 /* Transmit Stopped */ + +#define DMA_INTR_ABNORMAL (DMA_INTR_ENA_AIE | DMA_INTR_ENA_FBE | \ + DMA_INTR_ENA_UNE) + +/* DMA default interrupt mask */ +#define DMA_INTR_DEFAULT_MASK (DMA_INTR_NORMAL | DMA_INTR_ABNORMAL) + +/* DMA Status register defines */ +#define DMA_STATUS_GPI 0x10000000 /* PMT interrupt */ +#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */ +#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int */ +#define DMA_STATUS_GMI 0x08000000 +#define DMA_STATUS_GLI 0x04000000 +#define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */ +#define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */ +#define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */ +#define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */ +#define DMA_STATUS_TS_SHIFT 20 +#define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */ +#define DMA_STATUS_RS_SHIFT 17 +#define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */ +#define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */ +#define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */ +#define DMA_STATUS_FBI 0x00002000 /* Fatal Bus Error Interrupt */ +#define DMA_STATUS_ETI 0x00000400 /* Early Transmit Interrupt */ +#define DMA_STATUS_RWT 0x00000200 /* Receive Watchdog Timeout */ +#define DMA_STATUS_RPS 0x00000100 /* Receive Process Stopped */ +#define DMA_STATUS_RU 0x00000080 /* Receive Buffer Unavailable */ +#define DMA_STATUS_RI 0x00000040 /* Receive Interrupt */ +#define DMA_STATUS_UNF 0x00000020 /* Transmit Underflow */ +#define DMA_STATUS_OVF 0x00000010 /* Receive Overflow */ +#define DMA_STATUS_TJT 0x00000008 /* Transmit Jabber Timeout */ +#define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavailable */ +#define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */ +#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */ +#define DMA_CONTROL_FTF 0x00100000 /* Flush transmit FIFO */ + +extern void dwmac_enable_dma_transmission(void __iomem *ioaddr); +extern void dwmac_enable_dma_irq(void __iomem *ioaddr); +extern void dwmac_disable_dma_irq(void __iomem *ioaddr); +extern void dwmac_dma_start_tx(void __iomem *ioaddr); +extern void dwmac_dma_stop_tx(void __iomem *ioaddr); +extern void dwmac_dma_start_rx(void __iomem *ioaddr); +extern void dwmac_dma_stop_rx(void __iomem *ioaddr); +extern int dwmac_dma_interrupt(void __iomem *ioaddr, + struct stmmac_extra_stats *x); diff -uarN a/drivers/net/xmmac/dwmac_lib.c b/drivers/net/xmmac/dwmac_lib.c --- a/drivers/net/xmmac/dwmac_lib.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/dwmac_lib.c 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,258 @@ +/******************************************************************************* + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include +#include "common.h" +#include "dwmac_dma.h" + +#undef DWMAC_DMA_DEBUG +#ifdef DWMAC_DMA_DEBUG +#define DWMAC_LIB_DBG(fmt, args...) printk(fmt, ## args) +#else +#define DWMAC_LIB_DBG(fmt, args...) do { } while (0) +#endif + +/* CSR1 enables the transmit DMA to check for new descriptor */ +void dwmac_enable_dma_transmission(void __iomem *ioaddr) +{ + writel(1, ioaddr + DMA_XMT_POLL_DEMAND); +} + +void dwmac_enable_dma_irq(void __iomem *ioaddr) +{ + writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA); +} + +void dwmac_disable_dma_irq(void __iomem *ioaddr) +{ + writel(0, ioaddr + DMA_INTR_ENA); +} + +void dwmac_dma_start_tx(void __iomem *ioaddr) +{ + u32 value = readl(ioaddr + DMA_CONTROL); + value |= DMA_CONTROL_ST; + writel(value, ioaddr + DMA_CONTROL); +} + +void dwmac_dma_stop_tx(void __iomem *ioaddr) +{ + u32 value = readl(ioaddr + DMA_CONTROL); + value &= ~DMA_CONTROL_ST; + writel(value, ioaddr + DMA_CONTROL); +} + +void dwmac_dma_start_rx(void __iomem *ioaddr) +{ + u32 value = readl(ioaddr + DMA_CONTROL); + value |= DMA_CONTROL_SR; + writel(value, ioaddr + DMA_CONTROL); +} + +void dwmac_dma_stop_rx(void __iomem *ioaddr) +{ + u32 value = readl(ioaddr + DMA_CONTROL); + value &= ~DMA_CONTROL_SR; + writel(value, ioaddr + DMA_CONTROL); +} + +#ifdef DWMAC_DMA_DEBUG +static void show_tx_process_state(unsigned int status) +{ + unsigned int state; + state = (status & DMA_STATUS_TS_MASK) >> DMA_STATUS_TS_SHIFT; + + switch (state) { + case 0: + pr_info("- TX (Stopped): Reset or Stop command\n"); + break; + case 1: + pr_info("- TX (Running):Fetching the Tx desc\n"); + break; + case 2: + pr_info("- TX (Running): Waiting for end of tx\n"); + break; + case 3: + pr_info("- TX (Running): Reading the data " + "and queuing the data into the Tx buf\n"); + break; + case 6: + pr_info("- TX (Suspended): Tx Buff Underflow " + "or an unavailable Transmit descriptor\n"); + break; + case 7: + pr_info("- TX (Running): Closing Tx descriptor\n"); + break; + default: + break; + } +} + +static void show_rx_process_state(unsigned int status) +{ + unsigned int state; + state = (status & DMA_STATUS_RS_MASK) >> DMA_STATUS_RS_SHIFT; + + switch (state) { + case 0: + pr_info("- RX (Stopped): Reset or Stop command\n"); + break; + case 1: + pr_info("- RX (Running): Fetching the Rx desc\n"); + break; + case 2: + pr_info("- RX (Running):Checking for end of pkt\n"); + break; + case 3: + pr_info("- RX (Running): Waiting for Rx pkt\n"); + break; + case 4: + pr_info("- RX (Suspended): Unavailable Rx buf\n"); + break; + case 5: + pr_info("- RX (Running): Closing Rx descriptor\n"); + break; + case 6: + pr_info("- RX(Running): Flushing the current frame" + " from the Rx buf\n"); + break; + case 7: + pr_info("- RX (Running): Queuing the Rx frame" + " from the Rx buf into memory\n"); + break; + default: + break; + } +} +#endif + +int dwmac_dma_interrupt(void __iomem *ioaddr, + struct stmmac_extra_stats *x) +{ + int ret = 0; + /* read the status register (CSR5) */ + u32 intr_status = readl(ioaddr + DMA_STATUS); + + DWMAC_LIB_DBG(KERN_INFO "%s: [CSR5: 0x%08x]\n", __func__, intr_status); +#ifdef DWMAC_DMA_DEBUG + /* It displays the DMA process states (CSR5 register) */ + show_tx_process_state(intr_status); + show_rx_process_state(intr_status); +#endif + /* ABNORMAL interrupts */ + if (unlikely(intr_status & DMA_STATUS_AIS)) { + DWMAC_LIB_DBG(KERN_INFO "CSR5[15] DMA ABNORMAL IRQ: "); + if (unlikely(intr_status & DMA_STATUS_UNF)) { + DWMAC_LIB_DBG(KERN_INFO "transmit underflow\n"); + ret = tx_hard_error_bump_tc; + x->tx_undeflow_irq++; + } + if (unlikely(intr_status & DMA_STATUS_TJT)) { + DWMAC_LIB_DBG(KERN_INFO "transmit jabber\n"); + x->tx_jabber_irq++; + } + if (unlikely(intr_status & DMA_STATUS_OVF)) { + DWMAC_LIB_DBG(KERN_INFO "recv overflow\n"); + x->rx_overflow_irq++; + } + if (unlikely(intr_status & DMA_STATUS_RU)) { + DWMAC_LIB_DBG(KERN_INFO "receive buffer unavailable\n"); + x->rx_buf_unav_irq++; + } + if (unlikely(intr_status & DMA_STATUS_RPS)) { + DWMAC_LIB_DBG(KERN_INFO "receive process stopped\n"); + x->rx_process_stopped_irq++; + } + if (unlikely(intr_status & DMA_STATUS_RWT)) { + DWMAC_LIB_DBG(KERN_INFO "receive watchdog\n"); + x->rx_watchdog_irq++; + } + if (unlikely(intr_status & DMA_STATUS_ETI)) { + DWMAC_LIB_DBG(KERN_INFO "transmit early interrupt\n"); + x->tx_early_irq++; + } + if (unlikely(intr_status & DMA_STATUS_TPS)) { + DWMAC_LIB_DBG(KERN_INFO "transmit process stopped\n"); + x->tx_process_stopped_irq++; + ret = tx_hard_error; + } + if (unlikely(intr_status & DMA_STATUS_FBI)) { + DWMAC_LIB_DBG(KERN_INFO "fatal bus error\n"); + x->fatal_bus_error_irq++; + ret = tx_hard_error; + } + } + /* TX/RX NORMAL interrupts */ + if (intr_status & DMA_STATUS_NIS) { + x->normal_irq_n++; + if (likely((intr_status & DMA_STATUS_RI) || + (intr_status & (DMA_STATUS_TI)))) + ret = handle_tx_rx; + } + /* Optional hardware blocks, interrupts should be disabled */ + if (unlikely(intr_status & + (DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI))) + pr_info("%s: unexpected status %08x\n", __func__, intr_status); + /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */ + writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS); + + DWMAC_LIB_DBG(KERN_INFO "\n\n"); + return ret; +} + +void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr) +{ + u32 csr6 = readl(ioaddr + DMA_CONTROL); + writel((csr6 | DMA_CONTROL_FTF), ioaddr + DMA_CONTROL); + + do {} while ((readl(ioaddr + DMA_CONTROL) & DMA_CONTROL_FTF)); +} + +void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6], + unsigned int high, unsigned int low) +{ + unsigned long data; + + data = (addr[5] << 8) | addr[4]; + writel(data, ioaddr + high); + data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; + writel(data, ioaddr + low); +} + +void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, + unsigned int high, unsigned int low) +{ + unsigned int hi_addr, lo_addr; + + /* Read the MAC address from the hardware */ + hi_addr = readl(ioaddr + high); + lo_addr = readl(ioaddr + low); + + /* Extract the MAC address from the high and low words */ + addr[0] = lo_addr & 0xff; + addr[1] = (lo_addr >> 8) & 0xff; + addr[2] = (lo_addr >> 16) & 0xff; + addr[3] = (lo_addr >> 24) & 0xff; + addr[4] = hi_addr & 0xff; + addr[5] = (hi_addr >> 8) & 0xff; +} + diff -uarN a/drivers/net/xmmac/enh_desc.c b/drivers/net/xmmac/enh_desc.c --- a/drivers/net/xmmac/enh_desc.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/enh_desc.c 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,337 @@ +/******************************************************************************* + This contains the functions to handle the enhanced descriptors. + + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include "common.h" + +static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x, + struct dma_desc *p, void __iomem *ioaddr) +{ + int ret = 0; + struct net_device_stats *stats = (struct net_device_stats *)data; + + if (unlikely(p->des01.etx.error_summary)) { + CHIP_DBG(KERN_ERR "GMAC TX error... 0x%08x\n", p->des01.etx); + if (unlikely(p->des01.etx.jabber_timeout)) { + CHIP_DBG(KERN_ERR "\tjabber_timeout error\n"); + x->tx_jabber++; + } + + if (unlikely(p->des01.etx.frame_flushed)) { + CHIP_DBG(KERN_ERR "\tframe_flushed error\n"); + x->tx_frame_flushed++; + dwmac_dma_flush_tx_fifo(ioaddr); + } + + if (unlikely(p->des01.etx.loss_carrier)) { + CHIP_DBG(KERN_ERR "\tloss_carrier error\n"); + x->tx_losscarrier++; + stats->tx_carrier_errors++; + } + if (unlikely(p->des01.etx.no_carrier)) { + CHIP_DBG(KERN_ERR "\tno_carrier error\n"); + x->tx_carrier++; + stats->tx_carrier_errors++; + } + if (unlikely(p->des01.etx.late_collision)) { + CHIP_DBG(KERN_ERR "\tlate_collision error\n"); + stats->collisions += p->des01.etx.collision_count; + } + if (unlikely(p->des01.etx.excessive_collisions)) { + CHIP_DBG(KERN_ERR "\texcessive_collisions\n"); + stats->collisions += p->des01.etx.collision_count; + } + if (unlikely(p->des01.etx.excessive_deferral)) { + CHIP_DBG(KERN_INFO "\texcessive tx_deferral\n"); + x->tx_deferred++; + } + + if (unlikely(p->des01.etx.underflow_error)) { + CHIP_DBG(KERN_ERR "\tunderflow error\n"); + dwmac_dma_flush_tx_fifo(ioaddr); + x->tx_underflow++; + } + + if (unlikely(p->des01.etx.ip_header_error)) { + CHIP_DBG(KERN_ERR "\tTX IP header csum error\n"); + x->tx_ip_header_error++; + } + + if (unlikely(p->des01.etx.payload_error)) { + CHIP_DBG(KERN_ERR "\tAddr/Payload csum error\n"); + x->tx_payload_error++; + dwmac_dma_flush_tx_fifo(ioaddr); + } + + ret = -1; + } + + if (unlikely(p->des01.etx.deferred)) { + CHIP_DBG(KERN_INFO "GMAC TX status: tx deferred\n"); + x->tx_deferred++; + } +#ifdef STMMAC_VLAN_TAG_USED + if (p->des01.etx.vlan_frame) { + CHIP_DBG(KERN_INFO "GMAC TX status: VLAN frame\n"); + x->tx_vlan++; + } +#endif + + return ret; +} + +static int enh_desc_get_tx_len(struct dma_desc *p) +{ + return p->des01.etx.buffer1_size; +} + +static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err) +{ + int ret = good_frame; + u32 status = (type << 2 | ipc_err << 1 | payload_err) & 0x7; + + /* bits 5 7 0 | Frame status + * ---------------------------------------------------------- + * 0 0 0 | IEEE 802.3 Type frame (length < 1536 octects) + * 1 0 0 | IPv4/6 No CSUM errorS. + * 1 0 1 | IPv4/6 CSUM PAYLOAD error + * 1 1 0 | IPv4/6 CSUM IP HR error + * 1 1 1 | IPv4/6 IP PAYLOAD AND HEADER errorS + * 0 0 1 | IPv4/6 unsupported IP PAYLOAD + * 0 1 1 | COE bypassed.. no IPv4/6 frame + * 0 1 0 | Reserved. + */ + if (status == 0x0) { + CHIP_DBG(KERN_INFO "RX Des0 status: IEEE 802.3 Type frame.\n"); + ret = llc_snap; + } else if (status == 0x4) { + CHIP_DBG(KERN_INFO "RX Des0 status: IPv4/6 No CSUM errorS.\n"); + ret = good_frame; + } else if (status == 0x5) { + CHIP_DBG(KERN_ERR "RX Des0 status: IPv4/6 Payload Error.\n"); + ret = csum_none; + } else if (status == 0x6) { + CHIP_DBG(KERN_ERR "RX Des0 status: IPv4/6 Header Error.\n"); + ret = csum_none; + } else if (status == 0x7) { + CHIP_DBG(KERN_ERR + "RX Des0 status: IPv4/6 Header and Payload Error.\n"); + ret = csum_none; + } else if (status == 0x1) { + CHIP_DBG(KERN_ERR + "RX Des0 status: IPv4/6 unsupported IP PAYLOAD.\n"); + ret = discard_frame; + } else if (status == 0x3) { + CHIP_DBG(KERN_ERR "RX Des0 status: No IPv4, IPv6 frame.\n"); + ret = discard_frame; + } + return ret; +} + +static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x, + struct dma_desc *p) +{ + int ret = good_frame; + struct net_device_stats *stats = (struct net_device_stats *)data; + + if (unlikely(p->des01.erx.error_summary)) { + CHIP_DBG(KERN_ERR "GMAC RX Error Summary 0x%08x\n", + p->des01.erx); + if (unlikely(p->des01.erx.descriptor_error)) { + CHIP_DBG(KERN_ERR "\tdescriptor error\n"); + x->rx_desc++; + stats->rx_length_errors++; + } + if (unlikely(p->des01.erx.overflow_error)) { + CHIP_DBG(KERN_ERR "\toverflow error\n"); + x->rx_gmac_overflow++; + } + + if (unlikely(p->des01.erx.ipc_csum_error)) + CHIP_DBG(KERN_ERR "\tIPC Csum Error/Giant frame\n"); + + if (unlikely(p->des01.erx.late_collision)) { + CHIP_DBG(KERN_ERR "\tlate_collision error\n"); + stats->collisions++; + stats->collisions++; + } + if (unlikely(p->des01.erx.receive_watchdog)) { + CHIP_DBG(KERN_ERR "\treceive_watchdog error\n"); + x->rx_watchdog++; + } + if (unlikely(p->des01.erx.error_gmii)) { + CHIP_DBG(KERN_ERR "\tReceive Error\n"); + //x->rx_mii++; + } + if (unlikely(p->des01.erx.crc_error)) { + CHIP_DBG(KERN_ERR "\tCRC error\n"); + x->rx_crc++; + stats->rx_crc_errors++; + } + ret = discard_frame; + } + + /* After a payload csum error, the ES bit is set. + * It doesn't match with the information reported into the databook. + * At any rate, we need to understand if the CSUM hw computation is ok + * and report this info to the upper layers. */ + ret = enh_desc_coe_rdes0(p->des01.erx.ipc_csum_error, + p->des01.erx.frame_type, p->des01.erx.payload_csum_error); + + if (unlikely(p->des01.erx.dribbling)) { + CHIP_DBG(KERN_ERR "GMAC RX: dribbling error\n"); + ret = discard_frame; + } + if (unlikely(p->des01.erx.sa_filter_fail)) { + CHIP_DBG(KERN_ERR "GMAC RX : Source Address filter fail\n"); + x->sa_rx_filter_fail++; + ret = discard_frame; + } + if (unlikely(p->des01.erx.da_filter_fail)) { + CHIP_DBG(KERN_ERR "GMAC RX : Dest Address filter fail\n"); + x->da_rx_filter_fail++; + ret = discard_frame; + } + if (unlikely(p->des01.erx.length_error)) { + CHIP_DBG(KERN_ERR "GMAC RX: length_error error\n"); + x->rx_length++; + ret = discard_frame; + } +#ifdef STMMAC_VLAN_TAG_USED + if (p->des01.erx.vlan_tag) { + CHIP_DBG(KERN_INFO "GMAC RX: VLAN frame tagged\n"); + x->rx_vlan++; + } +#endif + return ret; +} + +static void enh_desc_init_rx_desc(struct dma_desc *p, unsigned int ring_size, + int disable_rx_ic) +{ + int i; + for (i = 0; i < ring_size; i++) { + p->des01.erx.own = 1; + p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1; + /* To support jumbo frames */ + p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1; + if (i == ring_size - 1) + p->des01.erx.end_ring = 1; + if (disable_rx_ic) + p->des01.erx.disable_ic = 1; + p++; + } +} + +static void enh_desc_init_tx_desc(struct dma_desc *p, unsigned int ring_size) +{ + int i; + + for (i = 0; i < ring_size; i++) { + p->des01.etx.own = 0; + if (i == ring_size - 1) + p->des01.etx.end_ring = 1; + p++; + } +} + +static int enh_desc_get_tx_owner(struct dma_desc *p) +{ + return p->des01.etx.own; +} + +static int enh_desc_get_rx_owner(struct dma_desc *p) +{ + return p->des01.erx.own; +} + +static void enh_desc_set_tx_owner(struct dma_desc *p) +{ + p->des01.etx.own = 1; +} + +static void enh_desc_set_rx_owner(struct dma_desc *p) +{ + p->des01.erx.own = 1; +} + +static int enh_desc_get_tx_ls(struct dma_desc *p) +{ + return p->des01.etx.last_segment; +} + +static void enh_desc_release_tx_desc(struct dma_desc *p) +{ + int ter = p->des01.etx.end_ring; + + memset(p, 0, offsetof(struct dma_desc, des2)); + p->des01.etx.end_ring = ter; +} + +static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len, + int csum_flag) +{ + p->des01.etx.first_segment = is_fs; + if (unlikely(len > BUF_SIZE_4KiB)) { + p->des01.etx.buffer1_size = BUF_SIZE_4KiB; + p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB; + } else { + p->des01.etx.buffer1_size = len; + } + if (likely(csum_flag)) + p->des01.etx.checksum_insertion = cic_full; +} + +static void enh_desc_clear_tx_ic(struct dma_desc *p) +{ + p->des01.etx.interrupt = 0; +} + +static void enh_desc_close_tx_desc(struct dma_desc *p) +{ + p->des01.etx.last_segment = 1; + p->des01.etx.interrupt = 1; +} + +static int enh_desc_get_rx_frame_len(struct dma_desc *p) +{ + return p->des01.erx.frame_length; +} + +const struct stmmac_desc_ops enh_desc_ops = { + .tx_status = enh_desc_get_tx_status, + .rx_status = enh_desc_get_rx_status, + .get_tx_len = enh_desc_get_tx_len, + .init_rx_desc = enh_desc_init_rx_desc, + .init_tx_desc = enh_desc_init_tx_desc, + .get_tx_owner = enh_desc_get_tx_owner, + .get_rx_owner = enh_desc_get_rx_owner, + .release_tx_desc = enh_desc_release_tx_desc, + .prepare_tx_desc = enh_desc_prepare_tx_desc, + .clear_tx_ic = enh_desc_clear_tx_ic, + .close_tx_desc = enh_desc_close_tx_desc, + .get_tx_ls = enh_desc_get_tx_ls, + .set_tx_owner = enh_desc_set_tx_owner, + .set_rx_owner = enh_desc_set_rx_owner, + .get_rx_frame_len = enh_desc_get_rx_frame_len, +}; diff -uarN a/drivers/net/xmmac/norm_desc.c b/drivers/net/xmmac/norm_desc.c --- a/drivers/net/xmmac/norm_desc.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/norm_desc.c 2018-12-26 09:52:58.000000000 +0300 @@ -0,0 +1,226 @@ +/******************************************************************************* + This contains the functions to handle the normal descriptors. + + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include "common.h" + +static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x, + struct dma_desc *p, void __iomem *ioaddr) +{ + int ret = 0; + struct net_device_stats *stats = (struct net_device_stats *)data; + + /************************************************** + * Edited By ZengChuanJie + * ***********************************************/ + if (unlikely(p->des01.tx.error_summary)) { + if (unlikely(p->des01.tx.underflow_error)) { + x->tx_underflow++; + stats->tx_fifo_errors++; + } + if (unlikely(p->des01.tx.no_carrier)) { + x->tx_carrier++; + stats->tx_carrier_errors++; + } + if (unlikely(p->des01.tx.loss_carrier)) { + x->tx_losscarrier++; + stats->tx_carrier_errors++; + } + if (unlikely((p->des01.tx.excessive_deferral) || + (p->des01.tx.excessive_collisions) || + (p->des01.tx.late_collision))) + stats->collisions += p->des01.tx.collision_count; + ret = -1; + } + if (unlikely(p->des01.tx.deferred)) + x->tx_deferred++; + /******** end ****************/ + + return ret; +} + +static int ndesc_get_tx_len(struct dma_desc *p) +{ + return p->des01.tx.buffer1_size; +} + +/* This function verifies if each incoming frame has some errors + * and, if required, updates the multicast statistics. + * In case of success, it returns csum_none because the device + * is not able to compute the csum in HW. */ +static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x, + struct dma_desc *p) +{ + int ret = csum_none; + struct net_device_stats *stats = (struct net_device_stats *)data; + + /************************************************ + * Edited By ZengChuanJie + * *********************************************/ + if (unlikely(p->des01.rx.last_descriptor == 0)) { + pr_warning("ndesc Error: Oversized Ethernet " + "frame spanned multiple buffers\n"); + stats->rx_length_errors++; + return discard_frame; + } + + if (unlikely(p->des01.rx.error_summary)) { + if (unlikely(p->des01.rx.descriptor_error)) { + x->rx_desc++; + } + if (unlikely(p->des01.rx.SAF)) { + x->sa_rx_filter_fail++; + } + if (unlikely(p->des01.rx.overflow_error)) { + stats->rx_over_errors++; + x->rx_gmac_overflow++; + } + if (unlikely(p->des01.rx.collision)) { + x->rx_collision++; + stats->collisions++; + } + if (unlikely(p->des01.rx.crc_error)) { + x->rx_crc++; + stats->rx_crc_errors++; + } + + ret = discard_frame; + } + if (unlikely(p->des01.rx.dribbling)) { + ret = discard_frame; + } + + if (unlikely(p->des01.rx.length_error)) { + x->rx_length++; + ret = discard_frame; + } + + if (unlikely(p->des01.rx.filtering_fail)) { + x->da_rx_filter_fail++; + ret = discard_frame; + } + /***********end*********/ + + return ret; +} + +static void ndesc_init_rx_desc(struct dma_desc *p, unsigned int ring_size, + int disable_rx_ic) +{ + int i; + for (i = 0; i < ring_size; i++) { + p->des01.rx.own = 1; + p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1; + if (i == ring_size - 1) + p->des01.rx.end_ring = 1; + if (disable_rx_ic) + p->des01.rx.disable_ic = 1; + p++; + } +} + +static void ndesc_init_tx_desc(struct dma_desc *p, unsigned int ring_size) +{ + int i; + for (i = 0; i < ring_size; i++) { + p->des01.tx.own = 0; + if (i == ring_size - 1) + p->des01.tx.end_ring = 1; + p++; + } +} + +static int ndesc_get_tx_owner(struct dma_desc *p) +{ + return p->des01.tx.own; +} + +static int ndesc_get_rx_owner(struct dma_desc *p) +{ + return p->des01.rx.own; +} + +static void ndesc_set_tx_owner(struct dma_desc *p) +{ + p->des01.tx.own = 1; +} + +static void ndesc_set_rx_owner(struct dma_desc *p) +{ + p->des01.rx.own = 1; +} + +static int ndesc_get_tx_ls(struct dma_desc *p) +{ + return p->des01.tx.last_segment; +} + +static void ndesc_release_tx_desc(struct dma_desc *p) +{ + int ter = p->des01.tx.end_ring; + + memset(p, 0, offsetof(struct dma_desc, des2)); + /* set termination field */ + p->des01.tx.end_ring = ter; +} + +static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len, + int csum_flag) +{ + p->des01.tx.first_segment = is_fs; + p->des01.tx.buffer1_size = len; +} + +static void ndesc_clear_tx_ic(struct dma_desc *p) +{ + p->des01.tx.interrupt = 0; +} + +static void ndesc_close_tx_desc(struct dma_desc *p) +{ + p->des01.tx.last_segment = 1; + p->des01.tx.interrupt = 1; +} + +static int ndesc_get_rx_frame_len(struct dma_desc *p) +{ + return p->des01.rx.frame_length; +} + +const struct stmmac_desc_ops ndesc_ops = { + .tx_status = ndesc_get_tx_status, + .rx_status = ndesc_get_rx_status, + .get_tx_len = ndesc_get_tx_len, + .init_rx_desc = ndesc_init_rx_desc, + .init_tx_desc = ndesc_init_tx_desc, + .get_tx_owner = ndesc_get_tx_owner, + .get_rx_owner = ndesc_get_rx_owner, + .release_tx_desc = ndesc_release_tx_desc, + .prepare_tx_desc = ndesc_prepare_tx_desc, + .clear_tx_ic = ndesc_clear_tx_ic, + .close_tx_desc = ndesc_close_tx_desc, + .get_tx_ls = ndesc_get_tx_ls, + .set_tx_owner = ndesc_set_tx_owner, + .set_rx_owner = ndesc_set_rx_owner, + .get_rx_frame_len = ndesc_get_rx_frame_len, +}; diff -uarN a/drivers/net/xmmac/source/Makefile b/drivers/net/xmmac/source/Makefile --- a/drivers/net/xmmac/source/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/source/Makefile 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,5 @@ +obj-$(CONFIG_STMMAC_ETH) += stmmac.o +stmmac-$(CONFIG_STMMAC_TIMER) += stmmac_timer.o +stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \ + dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \ + dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o $(stmmac-y) diff -uarN a/drivers/net/xmmac/source/_dwmac100_core.c b/drivers/net/xmmac/source/_dwmac100_core.c --- a/drivers/net/xmmac/source/_dwmac100_core.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/source/_dwmac100_core.c 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,207 @@ +/******************************************************************************* + This is the driver for the MAC 10/100 on-chip Ethernet controller + currently tested on all the ST boards based on STb7109 and stx7200 SoCs. + + DWC Ether MAC 10/100 Universal version 4.0 has been used for developing + this code. + + This only implements the mac core functions for this chip. + + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include +#include "dwmac100.h" + +static void dwmac100_core_init(void __iomem *ioaddr) +{ + u32 value = readl(ioaddr + MAC_CONTROL); + + writel((value | MAC_CORE_INIT), ioaddr + MAC_CONTROL); + +} + +static int dwmac100_rx_coe_supported(void __iomem *ioaddr) +{ + return 0; +} + +static void dwmac100_dump_mac_regs(void __iomem *ioaddr) +{ + pr_info("\t----------------------------------------------\n" + "\t DWMAC 100 CSR (base addr = 0x%p)\n" + "\t----------------------------------------------\n", + ioaddr); + pr_info("\tcontrol reg (offset 0x%x): 0x%08x\n", MAC_CONTROL, + readl(ioaddr + MAC_CONTROL)); + pr_info("\taddr HI (offset 0x%x): 0x%08x\n ", MAC_ADDR_HIGH, + readl(ioaddr + MAC_ADDR_HIGH)); + pr_info("\taddr LO (offset 0x%x): 0x%08x\n", MAC_ADDR_LOW, + readl(ioaddr + MAC_ADDR_LOW)); + pr_info("\tmulticast hash HI (offset 0x%x): 0x%08x\n", + MAC_HASH_HIGH, readl(ioaddr + MAC_HASH_HIGH)); + pr_info("\tmulticast hash LO (offset 0x%x): 0x%08x\n", + MAC_HASH_LOW, readl(ioaddr + MAC_HASH_LOW)); + pr_info("\tflow control (offset 0x%x): 0x%08x\n", + MAC_FLOW_CTRL, readl(ioaddr + MAC_FLOW_CTRL)); + pr_info("\tVLAN1 tag (offset 0x%x): 0x%08x\n", MAC_VLAN1, + readl(ioaddr + MAC_VLAN1)); + pr_info("\tVLAN2 tag (offset 0x%x): 0x%08x\n", MAC_VLAN2, + readl(ioaddr + MAC_VLAN2)); + pr_info("\n\tMAC management counter registers\n"); + pr_info("\t MMC crtl (offset 0x%x): 0x%08x\n", + MMC_CONTROL, readl(ioaddr + MMC_CONTROL)); + pr_info("\t MMC High Interrupt (offset 0x%x): 0x%08x\n", + MMC_HIGH_INTR, readl(ioaddr + MMC_HIGH_INTR)); + pr_info("\t MMC Low Interrupt (offset 0x%x): 0x%08x\n", + MMC_LOW_INTR, readl(ioaddr + MMC_LOW_INTR)); + pr_info("\t MMC High Interrupt Mask (offset 0x%x): 0x%08x\n", + MMC_HIGH_INTR_MASK, readl(ioaddr + MMC_HIGH_INTR_MASK)); + pr_info("\t MMC Low Interrupt Mask (offset 0x%x): 0x%08x\n", + MMC_LOW_INTR_MASK, readl(ioaddr + MMC_LOW_INTR_MASK)); +} + +static void dwmac100_irq_status(void __iomem *ioaddr) +{ + return; +} + +static void dwmac100_set_umac_addr(void __iomem *ioaddr, unsigned char *addr, + unsigned int reg_n) +{ + stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW); +} + +static void dwmac100_get_umac_addr(void __iomem *ioaddr, unsigned char *addr, + unsigned int reg_n) +{ + stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW); +} + +static void dwmac100_set_filter(struct net_device *dev) +{ + void __iomem *ioaddr = (void __iomem *) dev->base_addr; + u32 value = readl(ioaddr + MAC_CONTROL); + + if (dev->flags & IFF_PROMISC) { + /* 混杂模式下不会过滤任何地址 */ + value |= MAC_CONTROL_PR; + value &= ~(MAC_CONTROL_PM | MAC_CONTROL_IF | MAC_CONTROL_HO | + MAC_CONTROL_HP); + } else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE) + || (dev->flags & IFF_ALLMULTI)) { + /* netdev_mc_count获取设备已经有了的多播地址数量 */ + value |= MAC_CONTROL_PM; + value &= ~(MAC_CONTROL_PR | MAC_CONTROL_IF | MAC_CONTROL_HO); + writel(0xffffffff, ioaddr + MAC_HASH_HIGH); + writel(0xffffffff, ioaddr + MAC_HASH_LOW); + } else if (netdev_mc_empty(dev)) { /* no multicast */ + /* + * 由于set_filter没有对外开放,只有调用set_multilist_addr的时候会调用set_filter + * 所以基本上不会进行这个分支 + */ + value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF | + MAC_CONTROL_HO | MAC_CONTROL_HP); + } else { + u32 mc_filter[2]; + struct netdev_hw_addr *ha; + + /* Perfect filter mode for physical address and Hash + filter for multicast */ + value |= MAC_CONTROL_HP; + value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | + MAC_CONTROL_IF | MAC_CONTROL_HO); + + memset(mc_filter, 0, sizeof(mc_filter)); + netdev_for_each_mc_addr(ha, dev) { + /* 高低过滤寄存器,一个加起来只能支持64个多播地址,但有可能多个多播地址对应同一位 */ + /* The upper 6 bits of the calculated CRC are used to + * index the contens of the hash table */ + int bit_nr = + ether_crc(ETH_ALEN, ha->addr) >> 26; + /* The most significant bit determines the register to + * use (H/L) while the other 5 bits determine the bit + * within the register. */ + mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); + } + writel(mc_filter[0], ioaddr + MAC_HASH_LOW); + writel(mc_filter[1], ioaddr + MAC_HASH_HIGH); + } + + writel(value, ioaddr + MAC_CONTROL); + + CHIP_DBG(KERN_INFO "%s: CTRL reg: 0x%08x Hash regs: " + "HI 0x%08x, LO 0x%08x\n", + __func__, readl(ioaddr + MAC_CONTROL), + readl(ioaddr + MAC_HASH_HIGH), readl(ioaddr + MAC_HASH_LOW)); +} + +static void dwmac100_flow_ctrl(void __iomem *ioaddr, unsigned int duplex, + unsigned int fc, unsigned int pause_time) +{ + unsigned int flow = MAC_FLOW_CTRL_ENABLE; + + if (duplex) + flow |= (pause_time << MAC_FLOW_CTRL_PT_SHIFT); + writel(flow, ioaddr + MAC_FLOW_CTRL); +} + +/* No PMT module supported for this Ethernet Controller. + * Tested on ST platforms only. + */ +static void dwmac100_pmt(void __iomem *ioaddr, unsigned long mode) +{ + return; +} + +static const struct stmmac_ops dwmac100_ops = { + .core_init = dwmac100_core_init, + .rx_coe = dwmac100_rx_coe_supported, + .dump_regs = dwmac100_dump_mac_regs, + .host_irq_status = dwmac100_irq_status, + .set_filter = dwmac100_set_filter, + .flow_ctrl = dwmac100_flow_ctrl, + .pmt = dwmac100_pmt, + .set_umac_addr = dwmac100_set_umac_addr, + .get_umac_addr = dwmac100_get_umac_addr, +}; + +struct mac_device_info *dwmac100_setup(void __iomem *ioaddr) +{ + struct mac_device_info *mac; + + mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL); + if (!mac) + return NULL; + + pr_info("\tDWMAC100\n"); + + mac->mac = &dwmac100_ops; + mac->dma = &dwmac100_dma_ops; + + mac->link.port = MAC_CONTROL_PS; + mac->link.duplex = MAC_CONTROL_F; + mac->link.speed = 0; + mac->mii.addr = MAC_MII_ADDR; + mac->mii.data = MAC_MII_DATA; + + return mac; +} diff -uarN a/drivers/net/xmmac/source/common.h b/drivers/net/xmmac/source/common.h --- a/drivers/net/xmmac/source/common.h 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/source/common.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,252 @@ +/******************************************************************************* + STMMAC Common Header File + + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) +#define STMMAC_VLAN_TAG_USED +#include +#endif + +#include "descs.h" + +#undef CHIP_DEBUG_PRINT +/* Turn-on extra printk debug for MAC core, dma and descriptors */ +/* #define CHIP_DEBUG_PRINT */ + +#ifdef CHIP_DEBUG_PRINT +#define CHIP_DBG(fmt, args...) printk(fmt, ## args) +#else +#define CHIP_DBG(fmt, args...) do { } while (0) +#endif + +#undef FRAME_FILTER_DEBUG +/* #define FRAME_FILTER_DEBUG */ + +struct stmmac_extra_stats { + /* Transmit errors */ + unsigned long tx_underflow ____cacheline_aligned; + unsigned long tx_carrier; + unsigned long tx_losscarrier; + unsigned long tx_heartbeat; + unsigned long tx_deferred; + unsigned long tx_vlan; + unsigned long tx_jabber; + unsigned long tx_frame_flushed; + unsigned long tx_payload_error; + unsigned long tx_ip_header_error; + /* Receive errors */ + unsigned long rx_desc; + unsigned long rx_partial; + unsigned long rx_runt; + unsigned long rx_toolong; + unsigned long rx_collision; + unsigned long rx_crc; + unsigned long rx_length; + unsigned long rx_mii; + unsigned long rx_multicast; + unsigned long rx_gmac_overflow; + unsigned long rx_watchdog; + unsigned long da_rx_filter_fail; + unsigned long sa_rx_filter_fail; + unsigned long rx_missed_cntr; + unsigned long rx_overflow_cntr; + unsigned long rx_vlan; + /* Tx/Rx IRQ errors */ + unsigned long tx_undeflow_irq; + unsigned long tx_process_stopped_irq; + unsigned long tx_jabber_irq; + unsigned long rx_overflow_irq; + unsigned long rx_buf_unav_irq; + unsigned long rx_process_stopped_irq; + unsigned long rx_watchdog_irq; + unsigned long tx_early_irq; + unsigned long fatal_bus_error_irq; + /* Extra info */ + unsigned long threshold; + unsigned long tx_pkt_n; + unsigned long rx_pkt_n; + unsigned long poll_n; + unsigned long sched_timer_n; + unsigned long normal_irq_n; +}; + +#define HASH_TABLE_SIZE 64 +#define PAUSE_TIME 0x200 + +/* Flow Control defines */ +#define FLOW_OFF 0 +#define FLOW_RX 1 +#define FLOW_TX 2 +#define FLOW_AUTO (FLOW_TX | FLOW_RX) + +#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */ + +enum rx_frame_status { /* IPC status */ + good_frame = 0, + discard_frame = 1, + csum_none = 2, + llc_snap = 4, +}; + +enum tx_dma_irq_status { + tx_hard_error = 1, + tx_hard_error_bump_tc = 2, + handle_tx_rx = 3, +}; + +/* GMAC TX FIFO is 8K, Rx FIFO is 16K */ +#define BUF_SIZE_16KiB 16384 +#define BUF_SIZE_8KiB 8192 +#define BUF_SIZE_4KiB 4096 +#define BUF_SIZE_2KiB 2048 + +/* Power Down and WOL */ +#define PMT_NOT_SUPPORTED 0 +#define PMT_SUPPORTED 1 + +/* Common MAC defines */ +#define MAC_CTRL_REG 0x00000000 /* MAC Control */ +#define MAC_ENABLE_TX 0x00000008 /* Transmitter Enable */ +#define MAC_RNABLE_RX 0x00000004 /* Receiver Enable */ + +/* MAC Management Counters register */ +#define MMC_CONTROL 0x00000100 /* MMC Control */ +#define MMC_HIGH_INTR 0x00000104 /* MMC High Interrupt */ +#define MMC_LOW_INTR 0x00000108 /* MMC Low Interrupt */ +#define MMC_HIGH_INTR_MASK 0x0000010c /* MMC High Interrupt Mask */ +#define MMC_LOW_INTR_MASK 0x00000110 /* MMC Low Interrupt Mask */ + +#define MMC_CONTROL_MAX_FRM_MASK 0x0003ff8 /* Maximum Frame Size */ +#define MMC_CONTROL_MAX_FRM_SHIFT 3 +#define MMC_CONTROL_MAX_FRAME 0x7FF + +struct stmmac_desc_ops { + /* DMA RX descriptor ring initialization */ + void (*init_rx_desc) (struct dma_desc *p, unsigned int ring_size, + int disable_rx_ic); + /* DMA TX descriptor ring initialization */ + void (*init_tx_desc) (struct dma_desc *p, unsigned int ring_size); + + /* Invoked by the xmit function to prepare the tx descriptor */ + void (*prepare_tx_desc) (struct dma_desc *p, int is_fs, int len, + int csum_flag); + /* Set/get the owner of the descriptor */ + void (*set_tx_owner) (struct dma_desc *p); + int (*get_tx_owner) (struct dma_desc *p); + /* Invoked by the xmit function to close the tx descriptor */ + void (*close_tx_desc) (struct dma_desc *p); + /* Clean the tx descriptor as soon as the tx irq is received */ + void (*release_tx_desc) (struct dma_desc *p); + /* Clear interrupt on tx frame completion. When this bit is + * set an interrupt happens as soon as the frame is transmitted */ + void (*clear_tx_ic) (struct dma_desc *p); + /* Last tx segment reports the transmit status */ + int (*get_tx_ls) (struct dma_desc *p); + /* Return the transmit status looking at the TDES1 */ + int (*tx_status) (void *data, struct stmmac_extra_stats *x, + struct dma_desc *p, void __iomem *ioaddr); + /* Get the buffer size from the descriptor */ + int (*get_tx_len) (struct dma_desc *p); + /* Handle extra events on specific interrupts hw dependent */ + int (*get_rx_owner) (struct dma_desc *p); + void (*set_rx_owner) (struct dma_desc *p); + /* Get the receive frame size */ + int (*get_rx_frame_len) (struct dma_desc *p); + /* Return the reception status looking at the RDES1 */ + int (*rx_status) (void *data, struct stmmac_extra_stats *x, + struct dma_desc *p); +}; + +struct stmmac_dma_ops { + /* DMA core initialization */ + int (*init) (void __iomem *ioaddr, int pbl, u32 dma_tx, u32 dma_rx); + /* Dump DMA registers */ + void (*dump_regs) (void __iomem *ioaddr); + /* Set tx/rx threshold in the csr6 register + * An invalid value enables the store-and-forward mode */ + void (*dma_mode) (void __iomem *ioaddr, int txmode, int rxmode); + /* To track extra statistic (if supported) */ + void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x, + void __iomem *ioaddr); + void (*enable_dma_transmission) (void __iomem *ioaddr); + void (*enable_dma_irq) (void __iomem *ioaddr); + void (*disable_dma_irq) (void __iomem *ioaddr); + void (*start_tx) (void __iomem *ioaddr); + void (*stop_tx) (void __iomem *ioaddr); + void (*start_rx) (void __iomem *ioaddr); + void (*stop_rx) (void __iomem *ioaddr); + int (*dma_interrupt) (void __iomem *ioaddr, + struct stmmac_extra_stats *x); +}; + +struct stmmac_ops { + /* MAC core initialization */ + void (*core_init) (void __iomem *ioaddr) ____cacheline_aligned; + /* Support checksum offload engine */ + int (*rx_coe) (void __iomem *ioaddr); + /* Dump MAC registers */ + void (*dump_regs) (void __iomem *ioaddr); + /* Handle extra events on specific interrupts hw dependent */ + void (*host_irq_status) (void __iomem *ioaddr); + /* Multicast filter setting */ + void (*set_filter) (struct net_device *dev); + /* Flow control setting */ + void (*flow_ctrl) (void __iomem *ioaddr, unsigned int duplex, + unsigned int fc, unsigned int pause_time); + /* Set power management mode (e.g. magic frame) */ + void (*pmt) (void __iomem *ioaddr, unsigned long mode); + /* Set/Get Unicast MAC addresses */ + void (*set_umac_addr) (void __iomem *ioaddr, unsigned char *addr, + unsigned int reg_n); + void (*get_umac_addr) (void __iomem *ioaddr, unsigned char *addr, + unsigned int reg_n); +}; + +struct mac_link { + int port; + int duplex; + int speed; +}; + +struct mii_regs { + unsigned int addr; /* MII Address */ + unsigned int data; /* MII Data */ +}; + +struct mac_device_info { + const struct stmmac_ops *mac; + const struct stmmac_desc_ops *desc; + const struct stmmac_dma_ops *dma; + struct mii_regs mii; /* MII register Addresses */ + struct mac_link link; +}; + +struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr); +struct mac_device_info *dwmac100_setup(void __iomem *ioaddr); + +extern void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6], + unsigned int high, unsigned int low); +extern void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, + unsigned int high, unsigned int low); +extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr); diff -uarN a/drivers/net/xmmac/source/descs.h b/drivers/net/xmmac/source/descs.h --- a/drivers/net/xmmac/source/descs.h 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/source/descs.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,163 @@ +/******************************************************************************* + Header File to describe the DMA descriptors. + Enhanced descriptors have been in case of DWMAC1000 Cores. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ +struct dma_desc { + /* Receive descriptor */ + union { + struct { + /* RDES0 */ + u32 reserved1:1; + u32 crc_error:1; + u32 dribbling:1; + u32 mii_error:1; + u32 receive_watchdog:1; + u32 frame_type:1; + u32 collision:1; + u32 frame_too_long:1; + u32 last_descriptor:1; + u32 first_descriptor:1; + u32 multicast_frame:1; + u32 run_frame:1; + u32 length_error:1; + u32 partial_frame_error:1; + u32 descriptor_error:1; + u32 error_summary:1; + u32 frame_length:14; + u32 filtering_fail:1; + u32 own:1; + /* RDES1 */ + u32 buffer1_size:11; + u32 buffer2_size:11; + u32 reserved2:2; + u32 second_address_chained:1; + u32 end_ring:1; + u32 reserved3:5; + u32 disable_ic:1; + } rx; + struct { + /* RDES0 */ + u32 payload_csum_error:1; + u32 crc_error:1; + u32 dribbling:1; + u32 error_gmii:1; + u32 receive_watchdog:1; + u32 frame_type:1; + u32 late_collision:1; + u32 ipc_csum_error:1; + u32 last_descriptor:1; + u32 first_descriptor:1; + u32 vlan_tag:1; + u32 overflow_error:1; + u32 length_error:1; + u32 sa_filter_fail:1; + u32 descriptor_error:1; + u32 error_summary:1; + u32 frame_length:14; + u32 da_filter_fail:1; + u32 own:1; + /* RDES1 */ + u32 buffer1_size:13; + u32 reserved1:1; + u32 second_address_chained:1; + u32 end_ring:1; + u32 buffer2_size:13; + u32 reserved2:2; + u32 disable_ic:1; + } erx; /* -- enhanced -- */ + + /* Transmit descriptor */ + struct { + /* TDES0 */ + u32 deferred:1; + u32 underflow_error:1; + u32 excessive_deferral:1; + u32 collision_count:4; + u32 heartbeat_fail:1; + u32 excessive_collisions:1; + u32 late_collision:1; + u32 no_carrier:1; + u32 loss_carrier:1; + u32 reserved1:3; + u32 error_summary:1; + u32 reserved2:15; + u32 own:1; + /* TDES1 */ + u32 buffer1_size:11; + u32 buffer2_size:11; + u32 reserved3:1; + u32 disable_padding:1; + u32 second_address_chained:1; + u32 end_ring:1; + u32 crc_disable:1; + u32 reserved4:2; + u32 first_segment:1; + u32 last_segment:1; + u32 interrupt:1; + } tx; + struct { + /* TDES0 */ + u32 deferred:1; + u32 underflow_error:1; + u32 excessive_deferral:1; + u32 collision_count:4; + u32 vlan_frame:1; + u32 excessive_collisions:1; + u32 late_collision:1; + u32 no_carrier:1; + u32 loss_carrier:1; + u32 payload_error:1; + u32 frame_flushed:1; + u32 jabber_timeout:1; + u32 error_summary:1; + u32 ip_header_error:1; + u32 time_stamp_status:1; + u32 reserved1:2; + u32 second_address_chained:1; + u32 end_ring:1; + u32 checksum_insertion:2; + u32 reserved2:1; + u32 time_stamp_enable:1; + u32 disable_padding:1; + u32 crc_disable:1; + u32 first_segment:1; + u32 last_segment:1; + u32 interrupt:1; + u32 own:1; + /* TDES1 */ + u32 buffer1_size:13; + u32 reserved3:3; + u32 buffer2_size:13; + u32 reserved4:3; + } etx; /* -- enhanced -- */ + } des01; + unsigned int des2; + unsigned int des3; +}; + +/* Transmit checksum insertion control */ +enum tdes_csum_insertion { + cic_disabled = 0, /* Checksum Insertion Control */ + cic_only_ip = 1, /* Only IP header */ + cic_no_pseudoheader = 2, /* IP header but pseudoheader + * is not calculated */ + cic_full = 3, /* IP header and pseudoheader */ +}; diff -uarN a/drivers/net/xmmac/source/norm_desc.c b/drivers/net/xmmac/source/norm_desc.c --- a/drivers/net/xmmac/source/norm_desc.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/source/norm_desc.c 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,221 @@ +/******************************************************************************* + This contains the functions to handle the normal descriptors. + + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include "common.h" + +static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x, + struct dma_desc *p, void __iomem *ioaddr) +{ + int ret = 0; + struct net_device_stats *stats = (struct net_device_stats *)data; + + if (unlikely(p->des01.tx.error_summary)) { + if (unlikely(p->des01.tx.underflow_error)) { + x->tx_underflow++; + stats->tx_fifo_errors++; + } + if (unlikely(p->des01.tx.no_carrier)) { + x->tx_carrier++; + stats->tx_carrier_errors++; + } + if (unlikely(p->des01.tx.loss_carrier)) { + x->tx_losscarrier++; + stats->tx_carrier_errors++; + } + if (unlikely((p->des01.tx.excessive_deferral) || + (p->des01.tx.excessive_collisions) || + (p->des01.tx.late_collision))) + stats->collisions += p->des01.tx.collision_count; + ret = -1; + } + if (unlikely(p->des01.tx.heartbeat_fail)) { + x->tx_heartbeat++; + stats->tx_heartbeat_errors++; + ret = -1; + } + if (unlikely(p->des01.tx.deferred)) + x->tx_deferred++; + + return ret; +} + +static int ndesc_get_tx_len(struct dma_desc *p) +{ + return p->des01.tx.buffer1_size; +} + +/* This function verifies if each incoming frame has some errors + * and, if required, updates the multicast statistics. + * In case of success, it returns csum_none because the device + * is not able to compute the csum in HW. */ +static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x, + struct dma_desc *p) +{ + int ret = csum_none; + struct net_device_stats *stats = (struct net_device_stats *)data; + + if (unlikely(p->des01.rx.last_descriptor == 0)) { + pr_warning("ndesc Error: Oversized Ethernet " + "frame spanned multiple buffers\n"); + stats->rx_length_errors++; + return discard_frame; + } + + if (unlikely(p->des01.rx.error_summary)) { + if (unlikely(p->des01.rx.descriptor_error)) + x->rx_desc++; + if (unlikely(p->des01.rx.partial_frame_error)) + x->rx_partial++; + if (unlikely(p->des01.rx.run_frame)) + x->rx_runt++; + if (unlikely(p->des01.rx.frame_too_long)) + x->rx_toolong++; + if (unlikely(p->des01.rx.collision)) { + x->rx_collision++; + stats->collisions++; + } + if (unlikely(p->des01.rx.crc_error)) { + x->rx_crc++; + stats->rx_crc_errors++; + } + ret = discard_frame; + } + if (unlikely(p->des01.rx.dribbling)) + ret = discard_frame; + + if (unlikely(p->des01.rx.length_error)) { + x->rx_length++; + ret = discard_frame; + } + if (unlikely(p->des01.rx.mii_error)) { + x->rx_mii++; + ret = discard_frame; + } + if (p->des01.rx.multicast_frame) { + x->rx_multicast++; + stats->multicast++; + } + return ret; +} + +static void ndesc_init_rx_desc(struct dma_desc *p, unsigned int ring_size, + int disable_rx_ic) +{ + int i; + for (i = 0; i < ring_size; i++) { + p->des01.rx.own = 1; + p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1; + if (i == ring_size - 1) + p->des01.rx.end_ring = 1; + if (disable_rx_ic) + p->des01.rx.disable_ic = 1; + p++; + } +} + +static void ndesc_init_tx_desc(struct dma_desc *p, unsigned int ring_size) +{ + int i; + for (i = 0; i < ring_size; i++) { + p->des01.tx.own = 0; + if (i == ring_size - 1) + p->des01.tx.end_ring = 1; + p++; + } +} + +static int ndesc_get_tx_owner(struct dma_desc *p) +{ + return p->des01.tx.own; +} + +static int ndesc_get_rx_owner(struct dma_desc *p) +{ + return p->des01.rx.own; +} + +static void ndesc_set_tx_owner(struct dma_desc *p) +{ + p->des01.tx.own = 1; +} + +static void ndesc_set_rx_owner(struct dma_desc *p) +{ + p->des01.rx.own = 1; +} + +static int ndesc_get_tx_ls(struct dma_desc *p) +{ + return p->des01.tx.last_segment; +} + +static void ndesc_release_tx_desc(struct dma_desc *p) +{ + int ter = p->des01.tx.end_ring; + + memset(p, 0, offsetof(struct dma_desc, des2)); + /* set termination field */ + p->des01.tx.end_ring = ter; +} + +static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len, + int csum_flag) +{ + p->des01.tx.first_segment = is_fs; + p->des01.tx.buffer1_size = len; +} + +static void ndesc_clear_tx_ic(struct dma_desc *p) +{ + p->des01.tx.interrupt = 0; +} + +static void ndesc_close_tx_desc(struct dma_desc *p) +{ + p->des01.tx.last_segment = 1; + p->des01.tx.interrupt = 1; +} + +static int ndesc_get_rx_frame_len(struct dma_desc *p) +{ + return p->des01.rx.frame_length; +} + +const struct stmmac_desc_ops ndesc_ops = { + .tx_status = ndesc_get_tx_status, + .rx_status = ndesc_get_rx_status, + .get_tx_len = ndesc_get_tx_len, + .init_rx_desc = ndesc_init_rx_desc, + .init_tx_desc = ndesc_init_tx_desc, + .get_tx_owner = ndesc_get_tx_owner, + .get_rx_owner = ndesc_get_rx_owner, + .release_tx_desc = ndesc_release_tx_desc, + .prepare_tx_desc = ndesc_prepare_tx_desc, + .clear_tx_ic = ndesc_clear_tx_ic, + .close_tx_desc = ndesc_close_tx_desc, + .get_tx_ls = ndesc_get_tx_ls, + .set_tx_owner = ndesc_set_tx_owner, + .set_rx_owner = ndesc_set_rx_owner, + .get_rx_frame_len = ndesc_get_rx_frame_len, +}; diff -uarN a/drivers/net/xmmac/stmmac.h b/drivers/net/xmmac/stmmac.h --- a/drivers/net/xmmac/stmmac.h 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/stmmac.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,97 @@ +/******************************************************************************* + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#define DRV_MODULE_VERSION "Nov_2010" +#include + +#include "common.h" +#ifdef CONFIG_STMMAC_TIMER +#include "stmmac_timer.h" +#endif + +struct stmmac_priv { + /* Frequently used values are kept adjacent for cache effect */ + struct dma_desc *dma_tx ____cacheline_aligned; + dma_addr_t dma_tx_phy; + struct sk_buff **tx_skbuff; + unsigned int cur_tx; + unsigned int dirty_tx; + unsigned int dma_tx_size; + int tx_coalesce; + + struct dma_desc *dma_rx ; + /* + * 在开始接收时,cur_rx=dirty_rx,主机每处理一帧cur_rx便向后面移动, + * 那么cur_rx和dirty_rx之间的距离便是接收了的帧数 + */ + unsigned int cur_rx; + unsigned int dirty_rx; + struct sk_buff **rx_skbuff; + dma_addr_t *rx_skbuff_dma; + struct sk_buff_head rx_recycle; + + struct net_device *dev; + dma_addr_t dma_rx_phy; + unsigned int dma_rx_size; + unsigned int dma_buf_sz; + struct device *device; + struct mac_device_info *hw; + void __iomem *ioaddr; + + struct stmmac_extra_stats xstats; + struct napi_struct napi; + + phy_interface_t phy_interface; + int phy_addr; + int phy_mask; + int (*phy_reset) (void *priv); + int rx_coe; + int no_csum_insertion; + + int phy_irq; + struct phy_device *phydev; + int oldlink; + int speed; + int oldduplex; + unsigned int flow_ctrl; + unsigned int pause; + struct mii_bus *mii; + + u32 msg_enable; + spinlock_t lock; + spinlock_t tx_lock; + int wolopts; + int wolenabled; +#ifdef CONFIG_STMMAC_TIMER + struct stmmac_timer *tm; +#endif +#ifdef STMMAC_VLAN_TAG_USED + struct vlan_group *vlgrp; +#endif + struct plat_stmmacenet_data *plat; +}; + +extern int stmmac_mdio_unregister(struct net_device *ndev); +extern int stmmac_mdio_register(struct net_device *ndev); +extern void stmmac_set_ethtool_ops(struct net_device *netdev); +extern const struct stmmac_desc_ops enh_desc_ops; +extern const struct stmmac_desc_ops ndesc_ops; diff -uarN a/drivers/net/xmmac/stmmac_ethtool.c b/drivers/net/xmmac/stmmac_ethtool.c --- a/drivers/net/xmmac/stmmac_ethtool.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/stmmac_ethtool.c 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,359 @@ +/******************************************************************************* + STMMAC Ethtool support + + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include +#include +#include +#include + + +#include +#include "stmmac.h" +#include "dwmac_dma.h" + +#define REG_SPACE_SIZE 0x1054 +#define MAC100_ETHTOOL_NAME "st_mac100" +#define GMAC_ETHTOOL_NAME "st_gmac" + +struct stmmac_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +#define STMMAC_STAT(m) \ + { #m, FIELD_SIZEOF(struct stmmac_extra_stats, m), \ + offsetof(struct stmmac_priv, xstats.m)} + +static const struct stmmac_stats stmmac_gstrings_stats[] = { + STMMAC_STAT(tx_underflow), + STMMAC_STAT(tx_carrier), + STMMAC_STAT(tx_losscarrier), + //STMMAC_STAT(tx_heartbeat), + STMMAC_STAT(tx_deferred), + STMMAC_STAT(tx_vlan), + STMMAC_STAT(rx_vlan), + STMMAC_STAT(tx_jabber), + STMMAC_STAT(tx_frame_flushed), + STMMAC_STAT(tx_payload_error), + STMMAC_STAT(tx_ip_header_error), + STMMAC_STAT(rx_desc), + //STMMAC_STAT(rx_partial), + //STMMAC_STAT(rx_runt), + //STMMAC_STAT(rx_toolong), + STMMAC_STAT(rx_collision), + STMMAC_STAT(rx_crc), + STMMAC_STAT(rx_length), + //STMMAC_STAT(rx_mii), + //STMMAC_STAT(rx_multicast), + STMMAC_STAT(rx_gmac_overflow), + STMMAC_STAT(rx_watchdog), + STMMAC_STAT(da_rx_filter_fail), + STMMAC_STAT(sa_rx_filter_fail), + STMMAC_STAT(rx_missed_cntr), + STMMAC_STAT(rx_overflow_cntr), + STMMAC_STAT(tx_undeflow_irq), + STMMAC_STAT(tx_process_stopped_irq), + STMMAC_STAT(tx_jabber_irq), + STMMAC_STAT(rx_overflow_irq), + STMMAC_STAT(rx_buf_unav_irq), + STMMAC_STAT(rx_process_stopped_irq), + STMMAC_STAT(rx_watchdog_irq), + STMMAC_STAT(tx_early_irq), + STMMAC_STAT(fatal_bus_error_irq), + STMMAC_STAT(threshold), + STMMAC_STAT(tx_pkt_n), + STMMAC_STAT(rx_pkt_n), + STMMAC_STAT(poll_n), + STMMAC_STAT(sched_timer_n), + STMMAC_STAT(normal_irq_n), +}; +#define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats) + +static void stmmac_ethtool_getdrvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + if (!priv->plat->has_gmac) + strcpy(info->driver, MAC100_ETHTOOL_NAME); + else + strcpy(info->driver, GMAC_ETHTOOL_NAME); + + strcpy(info->version, DRV_MODULE_VERSION); + info->fw_version[0] = '\0'; + info->n_stats = STMMAC_STATS_LEN; +} + +static int stmmac_ethtool_getsettings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct stmmac_priv *priv = netdev_priv(dev); + struct phy_device *phy = priv->phydev; + int rc; + if (phy == NULL) { + pr_err("%s: %s: PHY is not registered\n", + __func__, dev->name); + return -ENODEV; + } + if (!netif_running(dev)) { + pr_err("%s: interface is disabled: we cannot track " + "link speed / duplex setting\n", dev->name); + return -EBUSY; + } + cmd->transceiver = XCVR_INTERNAL; + spin_lock_irq(&priv->lock); + rc = phy_ethtool_gset(phy, cmd); + spin_unlock_irq(&priv->lock); + return rc; +} + +static int stmmac_ethtool_setsettings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct stmmac_priv *priv = netdev_priv(dev); + struct phy_device *phy = priv->phydev; + int rc; + + spin_lock(&priv->lock); + rc = phy_ethtool_sset(phy, cmd); + spin_unlock(&priv->lock); + + return rc; +} + +static u32 stmmac_ethtool_getmsglevel(struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + return priv->msg_enable; +} + +static void stmmac_ethtool_setmsglevel(struct net_device *dev, u32 level) +{ + struct stmmac_priv *priv = netdev_priv(dev); + priv->msg_enable = level; + +} + +static int stmmac_check_if_running(struct net_device *dev) +{ + if (!netif_running(dev)) + return -EBUSY; + return 0; +} + +static int stmmac_ethtool_get_regs_len(struct net_device *dev) +{ + return REG_SPACE_SIZE; +} + +static void stmmac_ethtool_gregs(struct net_device *dev, + struct ethtool_regs *regs, void *space) +{ + int i; + u32 *reg_space = (u32 *) space; + + struct stmmac_priv *priv = netdev_priv(dev); + + memset(reg_space, 0x0, REG_SPACE_SIZE); + + if (!priv->plat->has_gmac) { + /* MAC registers */ + for (i = 0; i < 12; i++) + reg_space[i] = readl(priv->ioaddr + (i * 4)); + /* DMA registers */ + for (i = 0; i < 9; i++) + reg_space[i + 12] = + readl(priv->ioaddr + (DMA_BUS_MODE + (i * 4))); + reg_space[22] = readl(priv->ioaddr + DMA_CUR_TX_BUF_ADDR); + reg_space[23] = readl(priv->ioaddr + DMA_CUR_RX_BUF_ADDR); + } else { + /* MAC registers */ + for (i = 0; i < 55; i++) + reg_space[i] = readl(priv->ioaddr + (i * 4)); + /* DMA registers */ + for (i = 0; i < 22; i++) + reg_space[i + 55] = + readl(priv->ioaddr + (DMA_BUS_MODE + (i * 4))); + } +} + +static void +stmmac_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct stmmac_priv *priv = netdev_priv(netdev); + + spin_lock(&priv->lock); + + pause->rx_pause = 0; + pause->tx_pause = 0; + pause->autoneg = priv->phydev->autoneg; + + if (priv->flow_ctrl & FLOW_RX) + pause->rx_pause = 1; + if (priv->flow_ctrl & FLOW_TX) + pause->tx_pause = 1; + + spin_unlock(&priv->lock); +} + +static int +stmmac_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct stmmac_priv *priv = netdev_priv(netdev); + struct phy_device *phy = priv->phydev; + int new_pause = FLOW_OFF; + int ret = 0; + + spin_lock(&priv->lock); + + if (pause->rx_pause) + new_pause |= FLOW_RX; + if (pause->tx_pause) + new_pause |= FLOW_TX; + + priv->flow_ctrl = new_pause; + phy->autoneg = pause->autoneg; + + if (phy->autoneg) { + if (netif_running(netdev)) + ret = phy_start_aneg(phy); + } else + priv->hw->mac->flow_ctrl(priv->ioaddr, phy->duplex, + priv->flow_ctrl, priv->pause); + spin_unlock(&priv->lock); + return ret; +} + +static void stmmac_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *dummy, u64 *data) +{ + struct stmmac_priv *priv = netdev_priv(dev); + int i; + + /* Update HW stats if supported */ + priv->hw->dma->dma_diagnostic_fr(&dev->stats, (void *) &priv->xstats, + priv->ioaddr); + + for (i = 0; i < STMMAC_STATS_LEN; i++) { + char *p = (char *)priv + stmmac_gstrings_stats[i].stat_offset; + data[i] = (stmmac_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p); + } +} + +static int stmmac_get_sset_count(struct net_device *netdev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return STMMAC_STATS_LEN; + default: + return -EOPNOTSUPP; + } +} + +static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data) +{ + int i; + u8 *p = data; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < STMMAC_STATS_LEN; i++) { + memcpy(p, stmmac_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + break; + default: + WARN_ON(1); + break; + } +} + +/* Currently only support WOL through Magic packet. */ +static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + spin_lock_irq(&priv->lock); + if (device_can_wakeup(priv->device)) { + wol->supported = WAKE_MAGIC | WAKE_UCAST; + wol->wolopts = priv->wolopts; + } + spin_unlock_irq(&priv->lock); +} + +static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct stmmac_priv *priv = netdev_priv(dev); + u32 support = WAKE_MAGIC | WAKE_UCAST; + + if (!device_can_wakeup(priv->device)) + return -EINVAL; + + if (wol->wolopts & ~support) + return -EINVAL; + + if (wol->wolopts) { + pr_info("stmmac: wakeup enable\n"); + device_set_wakeup_enable(priv->device, 1); + enable_irq_wake(dev->irq); + } else { + device_set_wakeup_enable(priv->device, 0); + disable_irq_wake(dev->irq); + } + + spin_lock_irq(&priv->lock); + priv->wolopts = wol->wolopts; + spin_unlock_irq(&priv->lock); + + return 0; +} + +static struct ethtool_ops stmmac_ethtool_ops = { + .begin = stmmac_check_if_running, + .get_drvinfo = stmmac_ethtool_getdrvinfo, + .get_settings = stmmac_ethtool_getsettings, + .set_settings = stmmac_ethtool_setsettings, + .get_msglevel = stmmac_ethtool_getmsglevel, + .set_msglevel = stmmac_ethtool_setmsglevel, + .get_regs = stmmac_ethtool_gregs, + .get_regs_len = stmmac_ethtool_get_regs_len, + .get_link = ethtool_op_get_link, + .get_pauseparam = stmmac_get_pauseparam, + .set_pauseparam = stmmac_set_pauseparam, + .get_ethtool_stats = stmmac_get_ethtool_stats, + .get_strings = stmmac_get_strings, + .get_wol = stmmac_get_wol, + .set_wol = stmmac_set_wol, + .get_sset_count = stmmac_get_sset_count, +}; + +void stmmac_set_ethtool_ops(struct net_device *netdev) +{ + SET_ETHTOOL_OPS(netdev, &stmmac_ethtool_ops); +} diff -uarN a/drivers/net/xmmac/stmmac_main.c b/drivers/net/xmmac/stmmac_main.c --- a/drivers/net/xmmac/stmmac_main.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/stmmac_main.c 2019-02-14 05:41:45.000000000 +0300 @@ -0,0 +1,1809 @@ +/* + * Author: ZengChuanJie + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "stmmac.h" + +#include +#include + +#include + +#define STMMAC_RESOURCE_NAME "xmmaceth" +#define PHY_RESOURCE_NAME "xmmacphy" + +#undef STMMAC_DEBUG +#ifdef STMMAC_DEBUG +#define DBG(nlevel, klevel, fmt, args...) \ + ((void)(netif_msg_##nlevel(priv) && \ + printk(KERN_##klevel fmt, ## args))) +#else +#define DBG(nlevel, klevel, fmt, args...) do { } while (0) +#endif + +#undef STMMAC_RX_DEBUG +#ifdef STMMAC_RX_DEBUG +#define RX_DBG(fmt, args...) printk(fmt, ## args) +#else +#define RX_DBG(fmt, args...) do { } while (0) +#endif + +#undef STMMAC_XMIT_DEBUG +#ifdef STMMAC_TX_DEBUG +#define TX_DBG(fmt, args...) printk(fmt, ## args) +#else +#define TX_DBG(fmt, args...) do { } while (0) +#endif + +#define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x) +#define JUMBO_LEN 9000 + +/* Module parameters */ +#define TX_TIMEO 5000 /* default 5 seconds */ +static int watchdog = TX_TIMEO; +module_param(watchdog, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(watchdog, "Transmit timeout in milliseconds"); + +static int debug = -1; /* -1: default, 0: no output, 16: all */ +module_param(debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Message Level (0: no output, 16: all)"); + +static int phyaddr = -1; +module_param(phyaddr, int, S_IRUGO); +MODULE_PARM_DESC(phyaddr, "Physical device address"); + +#define DMA_TX_SIZE 2048 +static int dma_txsize = DMA_TX_SIZE; +module_param(dma_txsize, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dma_txsize, "Number of descriptors in the TX list"); + +#define DMA_RX_SIZE 256 +static int dma_rxsize = DMA_RX_SIZE; +module_param(dma_rxsize, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dma_rxsize, "Number of descriptors in the RX list"); + +static int flow_ctrl = FLOW_AUTO; /* 默认开启流控 */ +module_param(flow_ctrl, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(flow_ctrl, "Flow control ability [on/off]"); + +static int pause = PAUSE_TIME; +module_param(pause, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(pause, "Flow Control Pause Time"); + +#define TC_DEFAULT 64 /* 当发送缓冲区达到一个阈值值时开始发送数据,使用默认值 */ +static int tc = TC_DEFAULT; +module_param(tc, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(tc, "DMA threshold control value"); + +#define DMA_BUFFER_SIZE BUF_SIZE_2KiB +static int buf_sz = DMA_BUFFER_SIZE; +module_param(buf_sz, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(buf_sz, "DMA buffer size"); + +static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE | + NETIF_MSG_LINK | NETIF_MSG_IFUP | + NETIF_MSG_IFDOWN | NETIF_MSG_TIMER); + +static irqreturn_t stmmac_interrupt(int irq, void *dev_id); + + +#define EDIT_ZENGCHUANJIE 1 + +/** + * stmmac_verify_args - verify the driver parameters. + * Description: it verifies if some wrong parameter is passed to the driver. + * Note that wrong parameters are replaced with the default values. + */ +static void stmmac_verify_args(void) +{ + if (unlikely(watchdog < 0)) + watchdog = TX_TIMEO; + if (unlikely(dma_rxsize < 0)) + dma_rxsize = DMA_RX_SIZE; + if (unlikely(dma_txsize < 0)) + dma_txsize = DMA_TX_SIZE; + if (unlikely((buf_sz < DMA_BUFFER_SIZE) || (buf_sz > BUF_SIZE_16KiB))) + buf_sz = DMA_BUFFER_SIZE; + if (unlikely(flow_ctrl > 1)) + flow_ctrl = FLOW_AUTO; + else if (likely(flow_ctrl < 0)) + flow_ctrl = FLOW_OFF; + if (unlikely((pause < 0) || (pause > 0xffff))) + pause = PAUSE_TIME; +} + +#if defined(STMMAC_XMIT_DEBUG) || defined(STMMAC_RX_DEBUG) +static void print_pkt(unsigned char *buf, int len) +{ + int j; + pr_info("len = %d byte, buf addr: 0x%p", len, buf); + for (j = 0; j < len; j++) { + if ((j % 16) == 0) + pr_info("\n %03x:", j); + pr_info(" %02x", buf[j]); + } + pr_info("\n"); +} +#endif + +/* minimum number of free TX descriptors required to wake up TX process */ +#define STMMAC_TX_THRESH(x) (x->dma_tx_size/4) + +static inline u32 stmmac_tx_avail(struct stmmac_priv *priv) +{ + /* cur_tx是指最后一个已经传送的的位置 */ + return priv->dirty_tx + priv->dma_tx_size - (priv->cur_tx+1); +} + +/* On some ST platforms, some HW system configuraton registers have to be + * set according to the link speed negotiated. + */ +static inline void stmmac_hw_fix_mac_speed(struct stmmac_priv *priv) +{ + struct phy_device *phydev = priv->phydev; + + if (likely(priv->plat->fix_mac_speed)) + priv->plat->fix_mac_speed(priv->plat->bsp_priv, + phydev->speed); +} + +/** + * stmmac_adjust_link + * @dev: net device structure + * Description: it adjusts the link parameters. + */ +static void stmmac_adjust_link(struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + struct phy_device *phydev = priv->phydev; + unsigned long flags; + int new_state = 0; + unsigned int fc = priv->flow_ctrl, pause_time = priv->pause; + + if (phydev == NULL) + return; + + DBG(probe, DEBUG, "stmmac_adjust_link: called. address %d link %d\n", + phydev->addr, phydev->link); + + spin_lock_irqsave(&priv->lock, flags); + if (phydev->link) { + u32 ctrl = readl(priv->ioaddr + MAC_CTRL_REG); + + /* Now we make sure that we can be in full duplex mode. + * If not, we operate in half-duplex mode. */ + if (phydev->duplex != priv->oldduplex) { + new_state = 1; + if (!(phydev->duplex)) + ctrl &= ~(1<<11); + else + ctrl |= 1<<11; + priv->oldduplex = phydev->duplex; + } + /* Flow Control operation */ + priv->hw->mac->flow_ctrl(priv->ioaddr, phydev->duplex, + fc, pause_time); + + if (phydev->speed != priv->speed) { + new_state = 1; + switch (phydev->speed) { + case 1000: + if (likely(priv->plat->has_gmac)) + ctrl &= ~priv->hw->link.port; + stmmac_hw_fix_mac_speed(priv); + break; + case 100: + { + ctrl |= 1<<14; + break; + } + case 10: + { + /* 网络退化为10M,或者10M网络时使用 */ + ctrl &= ~(1<<14); + break; + } + default: + if (netif_msg_link(priv)) + pr_warning("%s: Speed (%d) is not 10" + " or 100!\n", dev->name, phydev->speed); + break; + } + + priv->speed = phydev->speed; + } + + writel(ctrl, priv->ioaddr + MAC_CTRL_REG); + + if (!priv->oldlink) { + new_state = 1; + priv->oldlink = 1; + } + } else if (priv->oldlink) { + new_state = 1; + priv->oldlink = 0; + priv->speed = 0; + priv->oldduplex = -1; + } + + if (new_state && netif_msg_link(priv)) + phy_print_status(phydev); + + spin_unlock_irqrestore(&priv->lock, flags); + + DBG(probe, DEBUG, "stmmac_adjust_link: exiting\n"); +} + +/** + * stmmac_init_phy - PHY initialization + * @dev: net device structure + * Description: it initializes the driver's PHY state, and attaches the PHY + * to the mac driver. + * Return value: + * 0 on success + */ +static int stmmac_init_phy(struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + struct phy_device *phydev; + char phy_id[MII_BUS_ID_SIZE + 3]; + char bus_id[MII_BUS_ID_SIZE]; + + priv->oldlink = 0; + priv->speed = 0; + priv->oldduplex = -1; + + if (priv->phy_addr == -1) { + /* We don't have a PHY, so do nothing */ + return 0; + } + + snprintf(bus_id, MII_BUS_ID_SIZE, "%x", priv->plat->bus_id); + snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id, + priv->phy_addr); + pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id); + + phydev = phy_connect(dev, phy_id, &stmmac_adjust_link, + priv->phy_interface); + + if (IS_ERR(phydev)) { + pr_err("%s: Could not attach to PHY\n", dev->name); + return PTR_ERR(phydev); + } + + /* + * Broken HW is sometimes missing the pull-up resistor on the + * MDIO line, which results in reads to non-existent devices returning + * 0 rather than 0xffff. Catch this here and treat 0 as a non-existent + * device as well. + * Note: phydev->phy_id is the result of reading the UID PHY registers. + */ + if (phydev->phy_id == 0) { + phy_disconnect(phydev); + return -ENODEV; + } + pr_debug("stmmac_init_phy: %s: attached to PHY (UID 0x%x)" + " Link = %d\n", dev->name, phydev->phy_id, phydev->link); + + priv->phydev = phydev; + + return 0; +} + +static inline void stmmac_enable_mac(void __iomem *ioaddr) +{ + u32 value = readl(ioaddr + MAC_CTRL_REG); + + value |= MAC_RNABLE_RX | MAC_ENABLE_TX; + writel(value, ioaddr + MAC_CTRL_REG); +} + +static inline void stmmac_disable_mac(void __iomem *ioaddr) +{ + u32 value = readl(ioaddr + MAC_CTRL_REG); + + value &= ~(MAC_ENABLE_TX | MAC_RNABLE_RX); + writel(value, ioaddr + MAC_CTRL_REG); +} + +/** + * display_ring + * @p: pointer to the ring. + * @size: size of the ring. + * Description: display all the descriptors within the ring. + */ +static void display_ring(struct dma_desc *p, int size) +{ + struct tmp_s { + u64 a; + unsigned int b; + unsigned int c; + }; + int i; + for (i = 0; i < size; i++) { + struct tmp_s *x = (struct tmp_s *)(p + i); + pr_info("\t%d [0x%x]: DES0=0x%x DES1=0x%x BUF1=0x%x BUF2=0x%x", + i, (unsigned int)virt_to_phys(&p[i]), + (unsigned int)(x->a), (unsigned int)((x->a) >> 32), + x->b, x->c); + pr_info("\n"); + } +} + +/** + * init_dma_desc_rings - init the RX/TX descriptor rings + * @dev: net device structure + * Description: this function initializes the DMA RX/TX descriptors + * and allocates the socket buffers. + */ +static void init_dma_desc_rings(struct net_device *dev) +{ + int i; + struct stmmac_priv *priv = netdev_priv(dev); + struct sk_buff *skb; + unsigned int txsize = priv->dma_tx_size; + unsigned int rxsize = priv->dma_rx_size; + unsigned int bfsize = priv->dma_buf_sz; + int buff2_needed = 0, dis_ic = 0; + + /* Set the Buffer size according to the MTU; + * indeed, in case of jumbo we need to bump-up the buffer sizes. + */ + if (unlikely(dev->mtu >= BUF_SIZE_8KiB)) + bfsize = BUF_SIZE_16KiB; + else if (unlikely(dev->mtu >= BUF_SIZE_4KiB)) + bfsize = BUF_SIZE_8KiB; + else if (unlikely(dev->mtu >= BUF_SIZE_2KiB)) + bfsize = BUF_SIZE_4KiB; + else if (unlikely(dev->mtu >= DMA_BUFFER_SIZE)) + bfsize = BUF_SIZE_2KiB; + else + bfsize = DMA_BUFFER_SIZE; + + /* If the MTU exceeds 8k so use the second buffer in the chain */ + if (bfsize >= BUF_SIZE_8KiB) + buff2_needed = 1; + + DBG(probe, INFO, "stmmac: txsize %d, rxsize %d, bfsize %d\n", + txsize, rxsize, bfsize); + + priv->rx_skbuff_dma = kmalloc(rxsize * sizeof(dma_addr_t), GFP_KERNEL); + priv->rx_skbuff = + kmalloc(sizeof(struct sk_buff *) * rxsize, GFP_KERNEL); + priv->dma_rx = + (struct dma_desc *)dma_alloc_coherent(priv->device, + rxsize * + sizeof(struct dma_desc), + &priv->dma_rx_phy, + GFP_KERNEL); + priv->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * txsize, + GFP_KERNEL); + priv->dma_tx = + (struct dma_desc *)dma_alloc_coherent(priv->device, + txsize * + sizeof(struct dma_desc), + &priv->dma_tx_phy, + GFP_KERNEL); + + if ((priv->dma_rx == NULL) || (priv->dma_tx == NULL)) { + pr_err("%s:ERROR allocating the DMA Tx/Rx desc\n", __func__); + return; + } + + DBG(probe, INFO, "stmmac (%s) DMA desc rings: virt addr (Rx %p, " + "Tx %p)\n\tDMA phy addr (Rx 0x%08x, Tx 0x%08x)\n", + dev->name, priv->dma_rx, priv->dma_tx, + (unsigned int)priv->dma_rx_phy, (unsigned int)priv->dma_tx_phy); + + /* RX INITIALIZATION */ + DBG(probe, INFO, "stmmac: SKB addresses:\n" + "skb\t\tskb data\tdma data\n"); + + for (i = 0; i < rxsize; i++) { + struct dma_desc *p = priv->dma_rx + i; + + skb = netdev_alloc_skb_ip_align(dev, bfsize); + if (unlikely(skb == NULL)) { + pr_err("%s: Rx init fails; skb is NULL\n", __func__); + break; + } + priv->rx_skbuff[i] = skb; + priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data, + bfsize, DMA_FROM_DEVICE); + + p->des2 = priv->rx_skbuff_dma[i]; + /* 采用ring即环形队列方式 */ + if (unlikely(buff2_needed)) + p->des3 = p->des2 + BUF_SIZE_8KiB; + DBG(probe, INFO, "[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i], + priv->rx_skbuff[i]->data, priv->rx_skbuff_dma[i]); + } + priv->cur_rx = 0; + priv->dirty_rx = (unsigned int)(i - rxsize); + priv->dma_buf_sz = bfsize; + buf_sz = bfsize; + + /* TX INITIALIZATION */ + for (i = 0; i < txsize; i++) { + priv->tx_skbuff[i] = NULL; + priv->dma_tx[i].des2 = 0; + } + priv->dirty_tx = 0; + priv->cur_tx = 0; + + /* Clear the Rx/Tx descriptors */ + priv->hw->desc->init_rx_desc(priv->dma_rx, rxsize, dis_ic); + priv->hw->desc->init_tx_desc(priv->dma_tx, txsize); + + if (netif_msg_hw(priv)) { + pr_info("RX descriptor ring:\n"); + display_ring(priv->dma_rx, rxsize); + pr_info("TX descriptor ring:\n"); + display_ring(priv->dma_tx, txsize); + } +} + +static void dma_free_rx_skbufs(struct stmmac_priv *priv) +{ + int i; + + for (i = 0; i < priv->dma_rx_size; i++) { + if (priv->rx_skbuff[i]) { + dma_unmap_single(priv->device, priv->rx_skbuff_dma[i], + priv->dma_buf_sz, DMA_FROM_DEVICE); + dev_kfree_skb_any(priv->rx_skbuff[i]); + } + priv->rx_skbuff[i] = NULL; + } +} + +static void dma_free_tx_skbufs(struct stmmac_priv *priv) +{ + int i; + + for (i = 0; i < priv->dma_tx_size; i++) { + if (priv->tx_skbuff[i] != NULL) { + struct dma_desc *p = priv->dma_tx + i; + if (p->des2) + dma_unmap_single(priv->device, p->des2, + priv->hw->desc->get_tx_len(p), + DMA_TO_DEVICE); + /* dev_kfree_skb_any可以在中断上下文、非中断上下文引用 */ + dev_kfree_skb_any(priv->tx_skbuff[i]); + priv->tx_skbuff[i] = NULL; + } + } +} + +static void free_dma_desc_resources(struct stmmac_priv *priv) +{ + /* Release the DMA TX/RX socket buffers */ + dma_free_rx_skbufs(priv); + dma_free_tx_skbufs(priv); + + /* Free the region of consistent memory previously allocated for + * the DMA */ + dma_free_coherent(priv->device, + priv->dma_tx_size * sizeof(struct dma_desc), + priv->dma_tx, priv->dma_tx_phy); + dma_free_coherent(priv->device, + priv->dma_rx_size * sizeof(struct dma_desc), + priv->dma_rx, priv->dma_rx_phy); + kfree(priv->rx_skbuff_dma); + kfree(priv->rx_skbuff); + kfree(priv->tx_skbuff); +} + +/** + * stmmac_dma_operation_mode - HW DMA operation mode + * @priv : pointer to the private device structure. + * Description: it sets the DMA operation mode: tx/rx DMA thresholds + * or Store-And-Forward capability. + */ +static void stmmac_dma_operation_mode(struct stmmac_priv *priv) +{ + if (likely((priv->plat->tx_coe) && (!priv->no_csum_insertion))) { + /* In case of GMAC, SF mode has to be enabled + * to perform the TX COE. This depends on: + * 1) TX COE if actually supported + * 2) There is no bugged Jumbo frame support + * that needs to not insert csum in the TDES. + */ + priv->hw->dma->dma_mode(priv->ioaddr, + SF_DMA_MODE, SF_DMA_MODE); + tc = SF_DMA_MODE; + } else + priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE); +} + +/** + * stmmac_tx: + * @priv: private driver structure + * Description: it reclaims resources after transmission completes. + */ +static void stmmac_tx(struct stmmac_priv *priv) +{ + unsigned int txsize = priv->dma_tx_size; + + while (priv->dirty_tx != priv->cur_tx) { + int last; + unsigned int entry = priv->dirty_tx % txsize; + struct sk_buff *skb = priv->tx_skbuff[entry]; + struct dma_desc *p = priv->dma_tx + entry; + + /* Check if the descriptor is owned by the DMA. */ + if (priv->hw->desc->get_tx_owner(p)) + break; + + /* Verify tx error by looking at the last segment */ + last = priv->hw->desc->get_tx_ls(p); + if (likely(last)) { + int tx_error = + priv->hw->desc->tx_status(&priv->dev->stats, + &priv->xstats, p, + priv->ioaddr); + if (likely(tx_error == 0)) { + priv->dev->stats.tx_packets++; + priv->xstats.tx_pkt_n++; + } else + priv->dev->stats.tx_errors++; + } + TX_DBG("%s: curr %d, dirty %d\n", __func__, + priv->cur_tx, priv->dirty_tx); + + if (likely(p->des2)) + dma_unmap_single(priv->device, p->des2, + priv->hw->desc->get_tx_len(p), + DMA_TO_DEVICE); + if (unlikely(p->des3)) + p->des3 = 0; + + if (likely(skb != NULL)) { + dev_kfree_skb(skb); + priv->tx_skbuff[entry] = NULL; + } + + priv->hw->desc->release_tx_desc(p); + + entry = (++priv->dirty_tx) % txsize; + } + if (unlikely(netif_queue_stopped(priv->dev) && + stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv))) { + netif_tx_lock(priv->dev); + if (netif_queue_stopped(priv->dev) && + stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv)) { + TX_DBG("%s: restart transmit\n", __func__); + netif_wake_queue(priv->dev); + } + netif_tx_unlock(priv->dev); + } +} + +static inline void stmmac_enable_irq(struct stmmac_priv *priv) +{ + priv->hw->dma->enable_dma_irq(priv->ioaddr); +} + +static inline void stmmac_disable_irq(struct stmmac_priv *priv) +{ + priv->hw->dma->disable_dma_irq(priv->ioaddr); +} + +static int stmmac_has_work(struct stmmac_priv *priv) +{ + unsigned int has_work = 0; + int rxret, tx_work = 0; + + rxret = priv->hw->desc->get_rx_owner(priv->dma_rx + + (priv->cur_rx % priv->dma_rx_size)); + + if (priv->dirty_tx != priv->cur_tx) + tx_work = 1; + + if (likely(!rxret || tx_work)) + has_work = 1; + + return has_work; +} + +static inline void _stmmac_schedule(struct stmmac_priv *priv) +{ + if (likely(stmmac_has_work(priv))) { + stmmac_disable_irq(priv); + napi_schedule(&priv->napi); + } +} + + +/** + * stmmac_tx_err: + * @priv: pointer to the private device structure + * Description: it cleans the descriptors and restarts the transmission + * in case of errors. + */ +static void stmmac_tx_err(struct stmmac_priv *priv) +{ + + netif_stop_queue(priv->dev); + + priv->hw->dma->stop_tx(priv->ioaddr); + dma_free_tx_skbufs(priv); + priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size); + priv->dirty_tx = 0; + priv->cur_tx = 0; + priv->hw->dma->start_tx(priv->ioaddr); + + priv->dev->stats.tx_errors++; + netif_wake_queue(priv->dev); +} + + + + +void gpio_reset_phy(void) +{ + /* 输出低 */ + gpio_write(GPIO_OUT_EN | GPIO_OUT_LOW, 59); + mdelay(100); + /* 输出高 */ + gpio_write(GPIO_OUT_EN | GPIO_OUT_HIGH, 59); + mdelay(100); +} +static void stmmac_dma_interrupt(struct stmmac_priv *priv) +{ + int status; + + status = priv->hw->dma->dma_interrupt(priv->ioaddr, &priv->xstats); + if (likely(status == handle_tx_rx)) { + _stmmac_schedule(priv); + } + + else if (unlikely(status == tx_hard_error_bump_tc)) { + /* Try to bump up the dma threshold on this failure */ + if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) { + tc += 64; + priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE); + priv->xstats.threshold = tc; + } + } else if (unlikely(status == tx_hard_error)) + stmmac_tx_err(priv); +} + + +/** + * stmmac_open - open entry point of the driver + * @dev : pointer to the device structure. + * Description: + * This function is the open entry point of the driver. + * Return value: + * 0 on success and an appropriate (-)ve integer as defined in errno.h + * file on failure. + */ +static int stmmac_open(struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + int ret; + + + /* Check that the MAC address is valid. If its not, refuse + * to bring the device up. The user must specify an + * address using the following linux command: + * ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx */ + if (!is_valid_ether_addr(dev->dev_addr)) { + random_ether_addr(dev->dev_addr); + pr_warning("%s: generated random MAC address %pM\n", dev->name, + dev->dev_addr); + } + + //gpio_reset_phy(); + + stmmac_verify_args(); + + ret = stmmac_init_phy(dev); + if (unlikely(ret)) { + pr_err("%s: Cannot attach to PHY (error: %d)\n", __func__, ret); + goto open_error; + } + + /* Create and initialize the TX/RX descriptors chains. */ + priv->dma_tx_size = STMMAC_ALIGN(dma_txsize); + priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize); + priv->dma_buf_sz = STMMAC_ALIGN(buf_sz); + init_dma_desc_rings(dev); + + + /* DMA initialization and SW reset */ + ret = priv->hw->dma->init(priv->ioaddr, priv->plat->pbl, + priv->dma_tx_phy, priv->dma_rx_phy); + if (ret < 0) { + pr_err("%s: DMA initialization failed\n", __func__); + goto open_error; + } + + /* Copy the MAC addr into the HW */ + priv->hw->mac->set_umac_addr(priv->ioaddr, dev->dev_addr, 0); + /* If required, perform hw setup of the bus. */ + if (priv->plat->bus_setup) + priv->plat->bus_setup(priv->ioaddr); + /* Initialize the MAC Core */ + priv->hw->mac->core_init(priv->ioaddr); + + priv->rx_coe = priv->hw->mac->rx_coe(priv->ioaddr); + if (priv->rx_coe) + pr_info("stmmac: Rx Checksum Offload Engine supported\n"); + if (priv->plat->tx_coe) + pr_info("\tTX Checksum insertion supported\n"); + netdev_update_features(dev); + + /* Initialise the MMC (if present) to disable all interrupts. */ + writel(0xffffffff, priv->ioaddr + MMC_HIGH_INTR_MASK); + writel(0xffffffff, priv->ioaddr + MMC_LOW_INTR_MASK); + + /* Request the IRQ lines */ + ret = request_irq(dev->irq, stmmac_interrupt, + IRQF_SHARED, dev->name, dev); + if (unlikely(ret < 0)) { + pr_err("%s: ERROR: allocating the IRQ %d (error: %d)\n", + __func__, dev->irq, ret); + goto open_error; + } + + /* Enable the MAC Rx/Tx */ + stmmac_enable_mac(priv->ioaddr); + + /* Set the HW DMA mode and the COE */ + stmmac_dma_operation_mode(priv); + + /* Extra statistics */ + memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats)); + priv->xstats.threshold = tc; + + /* Start the ball rolling... */ + DBG(probe, DEBUG, "%s: DMA RX/TX processes started...\n", dev->name); + priv->hw->dma->start_tx(priv->ioaddr); + priv->hw->dma->start_rx(priv->ioaddr); + + /* Dump DMA/MAC registers */ + if (netif_msg_hw(priv)) { + priv->hw->mac->dump_regs(priv->ioaddr); + priv->hw->dma->dump_regs(priv->ioaddr); + } + + if (priv->phydev) + phy_start(priv->phydev); + + napi_enable(&priv->napi); + netif_start_queue(dev); + + return 0; + +open_error: + if (priv->phydev) + phy_disconnect(priv->phydev); + + return ret; +} + +/** + * stmmac_release - close entry point of the driver + * @dev : device pointer. + * Description: + * This is the stop entry point of the driver. + */ +static int stmmac_release(struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + /* Stop and disconnect the PHY */ + if (priv->phydev) { + phy_stop(priv->phydev); + phy_disconnect(priv->phydev); + priv->phydev = NULL; + } + + netif_stop_queue(dev); + + napi_disable(&priv->napi); + + /* Free the IRQ lines */ + free_irq(dev->irq, dev); + + /* Stop TX/RX DMA and clear the descriptors */ + priv->hw->dma->stop_tx(priv->ioaddr); + priv->hw->dma->stop_rx(priv->ioaddr); + + /* Release and free the Rx/Tx resources */ + free_dma_desc_resources(priv); + + /* Disable the MAC Rx/Tx */ + stmmac_disable_mac(priv->ioaddr); + + netif_carrier_off(dev); + + return 0; +} + + +/** + * stmmac_xmit: + * @skb : the socket buffer + * @dev : device pointer + * Description : Tx entry point of the driver. + */ +static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + unsigned int txsize = priv->dma_tx_size; + unsigned int entry; + int i, csum_insertion = 0; + int nfrags = skb_shinfo(skb)->nr_frags; /* 处理多个分散的缓冲区 */ + struct dma_desc *desc, *first; + unsigned int nopaged_len; + + /* 如果发现可用的缓冲区不足以容纳将要发送的缓冲区 */ + if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) { + if (!netif_queue_stopped(dev)) { + netif_stop_queue(dev); + /* This is a hard error, log it. */ + pr_err("%s: BUG! Tx Ring full when queue awake\n", + __func__); + } + return NETDEV_TX_BUSY; + } + + spin_lock(&priv->tx_lock); + entry = priv->cur_tx % txsize; + +#ifdef STMMAC_XMIT_DEBUG + if ((skb->len > ETH_FRAME_LEN) || nfrags) + pr_info("stmmac xmit:\n" + "\tskb addr %p - len: %d - nopaged_len: %d\n" + "\tn_frags: %d - ip_summed: %d - %s gso\n", + skb, skb->len, skb_headlen(skb), nfrags, skb->ip_summed, + !skb_is_gso(skb) ? "isn't" : "is"); +#endif + + desc = priv->dma_tx + entry; + first = desc; + +#ifdef STMMAC_XMIT_DEBUG + if ((nfrags > 0) || (skb->len > ETH_FRAME_LEN)) + pr_debug("stmmac xmit: skb len: %d, nopaged_len: %d,\n" + "\t\tn_frags: %d, ip_summed: %d\n", + skb->len, skb_headlen(skb), nfrags, skb->ip_summed); +#endif + priv->tx_skbuff[entry] = skb; + nopaged_len = skb_headlen(skb); + desc->des2 = dma_map_single(priv->device, skb->data, + nopaged_len, DMA_TO_DEVICE); + priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, + csum_insertion); + + for (i = 0; i < nfrags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + int len = frag->size; + + entry = (++priv->cur_tx) % txsize; + desc = priv->dma_tx + entry; + + TX_DBG("\t[entry %d] segment len: %d\n", entry, len); + desc->des2 = dma_map_page(priv->device, frag->page.p, + frag->page_offset, + len, DMA_TO_DEVICE); + priv->tx_skbuff[entry] = NULL; + priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion); + priv->hw->desc->set_tx_owner(desc); + } + + /* Interrupt on completition only for the latest segment */ + /* 上层传送多个分段下来,这些分段都属于同一个帧,所以最后一个分段是帧的最后部分 */ + priv->hw->desc->close_tx_desc(desc); + + /* To avoid raise condition */ + priv->hw->desc->set_tx_owner(first); + + priv->cur_tx++; + +#ifdef STMMAC_XMIT_DEBUG + if (netif_msg_pktdata(priv)) { + pr_info("stmmac xmit: current=%d, dirty=%d, entry=%d, " + "first=%p, nfrags=%d\n", + (priv->cur_tx % txsize), (priv->dirty_tx % txsize), + entry, first, nfrags); + display_ring(priv->dma_tx, txsize); + pr_info(">>> frame to be transmitted: "); + print_pkt(skb->data, skb->len); + } +#endif + /* + * 上面准备好的缓冲区可以进行发送,但是如果要连续进行下一次的传送,就需要判断下一次 + * 的可用的缓冲区 + */ + if (unlikely(stmmac_tx_avail(priv) <= (MAX_SKB_FRAGS + 1))) { + TX_DBG("%s: stop transmitted packets\n", __func__); + netif_stop_queue(dev); + } + + dev->stats.tx_bytes += skb->len; + + /* 发送Poll命令 */ + priv->hw->dma->enable_dma_transmission(priv->ioaddr); + + spin_unlock(&priv->tx_lock); + return NETDEV_TX_OK; +} + +static inline void stmmac_rx_refill(struct stmmac_priv *priv) +{ + unsigned int rxsize = priv->dma_rx_size; + int bfsize = priv->dma_buf_sz; + struct dma_desc *p = priv->dma_rx; + + for (; priv->cur_rx - priv->dirty_rx > 0; priv->dirty_rx++) { + /* 将已经处理了的sk_buff重新分配空间 */ + unsigned int entry = priv->dirty_rx % rxsize; + if (likely(priv->rx_skbuff[entry] == NULL)) { + struct sk_buff *skb; + + skb = __skb_dequeue(&priv->rx_recycle); + if (skb == NULL){ + skb = netdev_alloc_skb_ip_align(priv->dev, + bfsize); + } + + if (unlikely(skb == NULL)) + break; + + priv->rx_skbuff[entry] = skb; + priv->rx_skbuff_dma[entry] = + dma_map_single(priv->device, skb->data, bfsize, + DMA_FROM_DEVICE); + + (p + entry)->des2 = priv->rx_skbuff_dma[entry]; + RX_DBG(KERN_INFO "\trefill entry #%d\n", entry); + } + priv->hw->desc->set_rx_owner(p + entry); + } +} + +static int stmmac_rx(struct stmmac_priv *priv, int limit) +{ + unsigned int rxsize = priv->dma_rx_size; + unsigned int entry = priv->cur_rx % rxsize; + unsigned int next_entry; + unsigned int count = 0; + struct dma_desc *p = priv->dma_rx + entry; + struct dma_desc *p_next; + +#ifdef STMMAC_RX_DEBUG + if (netif_msg_hw(priv)) { + pr_debug(">>> stmmac_rx: descriptor ring:\n"); + display_ring(priv->dma_rx, rxsize); + } +#endif + count = 0; + while (!priv->hw->desc->get_rx_owner(p)) { + int status; + + if (count >= limit) + break; + + count++; + + next_entry = (++priv->cur_rx) % rxsize; + p_next = priv->dma_rx + next_entry; + prefetch(p_next); + + /* read the status of the incoming frame */ + status = (priv->hw->desc->rx_status(&priv->dev->stats, + &priv->xstats, p)); + if (unlikely(status == discard_frame)) { + priv->dev->stats.rx_errors++; + } else { + struct sk_buff *skb; + int frame_len; + + frame_len = priv->hw->desc->get_rx_frame_len(p); + /* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3 + * Type frames (LLC/LLC-SNAP) */ +#if !EDIT_ZENGCHUANJIE + /* + * 我们只在ethernet当中使用(frame_len>1536-0x800/0x806/0x808), 不会使用0x802.3帧, + * 在没有开启checksum的时候,FCS及其长度会被自动丢弃,所以frame_len不需要-4 + * 参考gmac文档p418,Table 6-32(IPCHKSUM_EN=0 && IPC_FULL_OFFLOAD=0) + * + */ + if (unlikely(status != llc_snap)) + frame_len -= ETH_FCS_LEN; +#endif +#ifdef STMMAC_RX_DEBUG + if (frame_len > ETH_FRAME_LEN) + pr_debug("\tRX frame size %d, COE status: %d\n", + frame_len, status); + + if (netif_msg_hw(priv)) + pr_debug("\tdesc: %p [entry %d] buff=0x%x\n", + p, entry, p->des2); +#endif + skb = priv->rx_skbuff[entry]; + if (unlikely(!skb)) { + pr_err("%s: Inconsistent Rx descriptor chain\n", + priv->dev->name); + priv->dev->stats.rx_dropped++; + break; + } + prefetch(skb->data - NET_IP_ALIGN); + priv->rx_skbuff[entry] = NULL; + + skb_put(skb, frame_len); + /* 如果该数据被cache了,那么需要将数据刷新到cache当中去 */ + dma_unmap_single(priv->device, + priv->rx_skbuff_dma[entry], + priv->dma_buf_sz, DMA_FROM_DEVICE); +#ifdef STMMAC_RX_DEBUG + if (netif_msg_pktdata(priv)) { + pr_info(" frame received (%dbytes)", frame_len); + print_pkt(skb->data, frame_len); + } +#endif + skb->protocol = eth_type_trans(skb, priv->dev); + +#if EDIT_ZENGCHUANJIE + /* always for the old mac 10/100 */ + skb_checksum_none_assert(skb); + netif_receive_skb(skb); +#else + /* 由于gmac ip没有开启l4 checksum以及ipv4 checksum + * 所以这里肯定是CHECKSUM_NONE, 这些校验必须由上层来完成 + * (目的在于简化驱动复杂度) + */ + if (unlikely(status == csum_none)) { + /* always for the old mac 10/100 */ + skb_checksum_none_assert(skb); + netif_receive_skb(skb); + } else { + skb->ip_summed = CHECKSUM_UNNECESSARY; + napi_gro_receive(&priv->napi, skb); + } +#endif + + priv->dev->stats.rx_packets++; + priv->dev->stats.rx_bytes += frame_len; + } + entry = next_entry; + p = p_next; /* use prefetched values */ + } + + /* + * 由于在接收的时候sk_buff是由驱动程序提供的,提供给协议处理函数并被上层处理后, + * skb_buff会被释放调,所以需要重新创建对应的sk_buff + */ + stmmac_rx_refill(priv); + + priv->xstats.rx_pkt_n += count; + + return count; +} + +/** + * stmmac_poll - stmmac poll method (NAPI) + * @napi : pointer to the napi structure. + * @budget : maximum number of packets that the current CPU can receive from + * all interfaces. + * Description : + * This function implements the the reception process. + * Also it runs the TX completion thread + */ +static int stmmac_poll(struct napi_struct *napi, int budget) +{ + struct stmmac_priv *priv = container_of(napi, struct stmmac_priv, napi); + int work_done = 0; + + priv->xstats.poll_n++; + /* 产生关于tx/rx的中断,就重新判断驱动程序缓冲区的能力,决定是否重新使能设备发送 */ + spin_lock(&priv->tx_lock); + stmmac_tx(priv); + spin_unlock(&priv->tx_lock); + work_done = stmmac_rx(priv, budget); + + if (work_done < budget) { + /* 如果接收的数量小于能够接收的配额,则表示全部接收完成,将当前napi + * 从softnet_data的poll_list当中移除(清除SCHED标识),如果下次中断产生 + * 再将当中设备的状态置为SCHED + */ + napi_complete(napi); + stmmac_enable_irq(priv); + } + return work_done; +} + +/** + * stmmac_tx_timeout + * @dev : Pointer to net device structure + * Description: this function is called when a packet transmission fails to + * complete within a reasonable tmrate. The driver will mark the error in the + * netdev structure and arrange for the device to be reset to a sane state + * in order to transmit a new packet. + */ +static void stmmac_tx_timeout(struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + /* Clear Tx resources and restart transmitting again */ + stmmac_tx_err(priv); +} + +/* Configuration changes (passed on by ifconfig) */ +static int stmmac_config(struct net_device *dev, struct ifmap *map) +{ + if (dev->flags & IFF_UP) /* can't act on a running interface */ + return -EBUSY; + + /* Don't allow changing the I/O address */ + if (map->base_addr != dev->base_addr) { + pr_warning("%s: can't change I/O address\n", dev->name); + return -EOPNOTSUPP; + } + + /* Don't allow changing the IRQ */ + if (map->irq != dev->irq) { + pr_warning("%s: can't change IRQ number %d\n", + dev->name, dev->irq); + return -EOPNOTSUPP; + } + + /* ignore other fields */ + return 0; +} + +/** + * stmmac_multicast_list - entry point for multicast addressing + * @dev : pointer to the device structure + * Description: + * This function is a driver entry point which gets called by the kernel + * whenever multicast addresses must be enabled/disabled. + * Return value: + * void. + */ +static void stmmac_multicast_list(struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + //printk(KERN_EMERG" Get In stmmac_multicast_list.\n"); + spin_lock(&priv->lock); + priv->hw->mac->set_filter(dev); + spin_unlock(&priv->lock); +} + +/** + * stmmac_change_mtu - entry point to change MTU size for the device. + * @dev : device pointer. + * @new_mtu : the new MTU size for the device. + * Description: the Maximum Transfer Unit (MTU) is used by the network layer + * to drive packet transmission. Ethernet has an MTU of 1500 octets + * (ETH_DATA_LEN). This value can be changed with ifconfig. + * Return value: + * 0 on success and an appropriate (-)ve integer as defined in errno.h + * file on failure. + */ +static int stmmac_change_mtu(struct net_device *dev, int new_mtu) +{ + struct stmmac_priv *priv = netdev_priv(dev); + int max_mtu; + + if (netif_running(dev)) { + pr_err("%s: must be stopped to change its MTU\n", dev->name); + return -EBUSY; + } + + if (priv->plat->has_gmac) + max_mtu = JUMBO_LEN; + else + max_mtu = ETH_DATA_LEN; + + if ((new_mtu < 46) || (new_mtu > max_mtu)) { + pr_err("%s: invalid MTU, max MTU is: %d\n", dev->name, max_mtu); + return -EINVAL; + } + + dev->mtu = new_mtu; + netdev_update_features(dev); + + return 0; +} + +static netdev_features_t stmmac_fix_features(struct net_device *dev, + netdev_features_t features) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + if (!priv->rx_coe) + features &= ~NETIF_F_RXCSUM; + if (!priv->plat->tx_coe) + features &= ~NETIF_F_ALL_CSUM; + + /* Some GMAC devices have a bugged Jumbo frame support that + * needs to have the Tx COE disabled for oversized frames + * (due to limited buffer sizes). In this case we disable + * the TX csum insertionin the TDES and not use SF. */ + if (priv->plat->bugged_jumbo && (dev->mtu > ETH_DATA_LEN)) + features &= ~NETIF_F_ALL_CSUM; + + return features; +} + +static irqreturn_t stmmac_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct stmmac_priv *priv = netdev_priv(dev); + + if (unlikely(!dev)) { + pr_err("%s: invalid dev pointer\n", __func__); + return IRQ_NONE; + } + + if (priv->plat->has_gmac) + /* To handle GMAC own interrupts */ + priv->hw->mac->host_irq_status((void __iomem *) dev->base_addr); + + stmmac_dma_interrupt(priv); + + return IRQ_HANDLED; +} + + +/** + * stmmac_ioctl - Entry point for the Ioctl + * @dev: Device pointer. + * @rq: An IOCTL specefic structure, that can contain a pointer to + * a proprietary structure used to pass information to the driver. + * @cmd: IOCTL command + * Description: + * Currently there are no special functionality supported in IOCTL, just the + * phy_mii_ioctl(...) can be invoked. + */ +static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct stmmac_priv *priv = netdev_priv(dev); + int ret; + + if (!netif_running(dev)) + return -EINVAL; + + if (!priv->phydev) + return -EINVAL; + + spin_lock(&priv->lock); + ret = phy_mii_ioctl(priv->phydev, rq, cmd); + spin_unlock(&priv->lock); + + return ret; +} + + +static const struct net_device_ops stmmac_netdev_ops = { + .ndo_open = stmmac_open, + .ndo_start_xmit = stmmac_xmit, + .ndo_stop = stmmac_release, + .ndo_change_mtu = stmmac_change_mtu, + .ndo_fix_features = stmmac_fix_features, + .ndo_set_rx_mode = stmmac_multicast_list, + /* 发送首先需要进入发送缓冲区队列,这个函数是缓冲区队列的某个元素一直迟迟没有被驱动程序的所处理 */ + .ndo_tx_timeout = stmmac_tx_timeout, + .ndo_do_ioctl = stmmac_ioctl, + .ndo_set_config = stmmac_config, + .ndo_set_mac_address = eth_mac_addr, +}; + +/** + * stmmac_probe - Initialization of the adapter . + * @dev : device pointer + * Description: The function initializes the network device structure for + * the STMMAC driver. It also calls the low level routines + * in order to init the HW (i.e. the DMA engine) + */ +static int stmmac_probe(struct net_device *dev) +{ + int ret = 0; + struct stmmac_priv *priv = netdev_priv(dev); + + ether_setup(dev); + + dev->netdev_ops = &stmmac_netdev_ops; + stmmac_set_ethtool_ops(dev); + + /* + * IP头部的校验和都是由软件完成的,hw_features不会指定ip头的校验 + * + * NETF_F_IP_CSUM表示硬件可以计算IPV4的L4校验 + * NETIF_F_HW_CSUM表示硬件可以计算所有协议的L4校验,在TCP/IP里面不会指定这个字段 + * NETIF_F_NO_CSUM表示这个硬件很可靠,不需要任何的校验检查,只适用于回环设备 + */ + dev->hw_features = NETIF_F_SG; /* 暂时不需要支持L4硬件校验 */ + dev->features |= dev->hw_features | NETIF_F_HIGHDMA; + dev->watchdog_timeo = msecs_to_jiffies(watchdog); + priv->msg_enable = netif_msg_init(debug, default_msg_level); + + if (flow_ctrl) /* 默认开启流控 */ + priv->flow_ctrl = FLOW_AUTO; /* RX/TX pause on */ + + priv->pause = pause; + netif_napi_add(dev, &priv->napi, stmmac_poll, 64); + + /* Get the MAC address */ + priv->hw->mac->get_umac_addr((void __iomem *) dev->base_addr, + dev->dev_addr, 0); + + if (!is_valid_ether_addr(dev->dev_addr)) + pr_warning("\tno valid MAC address;" + "please, use ifconfig or nwhwconfig!\n"); + + spin_lock_init(&priv->lock); + spin_lock_init(&priv->tx_lock); + + ret = register_netdev(dev); + if (ret) { + pr_err("%s: ERROR %i registering the device\n", + __func__, ret); + return -ENODEV; + } + + DBG(probe, DEBUG, "%s: Scatter/Gather: %s - HW checksums: %s\n", + dev->name, (dev->features & NETIF_F_SG) ? "on" : "off", + (dev->features & NETIF_F_IP_CSUM) ? "on" : "off"); + + return ret; +} + +/** + * stmmac_mac_device_setup + * @dev : device pointer + * Description: select and initialise the mac device (mac100 or Gmac). + */ +static int stmmac_mac_device_setup(struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + struct mac_device_info *device; + + if (priv->plat->has_gmac) { + device = dwmac1000_setup(priv->ioaddr); + } else { + device = dwmac100_setup(priv->ioaddr); + } + + if (!device) + return -ENOMEM; + + if (priv->plat->enh_desc) { + device->desc = &enh_desc_ops; + pr_info("\tEnhanced descriptor structure\n"); + } else { + device->desc = &ndesc_ops; + } + + priv->hw = device; + + return 0; +} + +static int stmmacphy_dvr_probe(struct platform_device *pdev) +{ + struct plat_stmmacphy_data *plat_dat = pdev->dev.platform_data; + + pr_debug("stmmacphy_dvr_probe: added phy for bus %d\n", + plat_dat->bus_id); + + return 0; +} + +static int stmmacphy_dvr_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver stmmacphy_driver = { + .driver = { + .name = PHY_RESOURCE_NAME, + }, + .probe = stmmacphy_dvr_probe, + .remove = stmmacphy_dvr_remove, +}; + +/** + * stmmac_associate_phy + * @dev:bus_ pointer to device structure + * @data: points to the private structure. + * Description: Scans through all the PHYs we have registered and checks if + * any are associated with our MAC. If so, then just fill in + * the blanks in our local context structure + */ +static int stmmac_associate_phy(struct device *dev, void *data) +{ + struct stmmac_priv *priv = (struct stmmac_priv *)data; + struct plat_stmmacphy_data *plat_dat = dev->platform_data; + + + DBG(probe, DEBUG, "%s: checking phy for bus %d\n", __func__, + plat_dat->bus_id); + + /* Check that this phy is for the MAC being initialised */ + if (priv->plat->bus_id != plat_dat->bus_id) + return 0; + + /* OK, this PHY is connected to the MAC. + Go ahead and get the parameters */ + DBG(probe, DEBUG, "%s: OK. Found PHY config\n", __func__); + + /* Override with kernel parameters if supplied XXX CRS XXX + * this needs to have multiple instances */ + if ((phyaddr >= 0) && (phyaddr <= 31)) + plat_dat->phy_addr = phyaddr; + + priv->phy_addr = plat_dat->phy_addr; + priv->phy_mask = plat_dat->phy_mask; + priv->phy_interface = plat_dat->interface; + priv->phy_reset = plat_dat->phy_reset; + + DBG(probe, DEBUG, "%s: exiting\n", __func__); + return 1; /* forces exit of driver_for_each_device() */ +} + +/** + * stmmac_dvr_probe + * @pdev: platform device pointer + * Description: the driver is initialized through platform_device. + */ +static int stmmac_dvr_probe(struct platform_device *pdev) +{ + int ret = 0; + struct resource *res; + void __iomem *addr = NULL; + struct net_device *ndev = NULL; + struct stmmac_priv *priv = NULL; + struct plat_stmmacenet_data *plat_dat; + + + pr_info("XMMMAC driver:\n\tplatform registration... "); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + pr_info("\tdone!\n"); + + if (!request_mem_region(res->start, resource_size(res), + pdev->name)) { + pr_err("%s: ERROR: memory allocation failed" + "cannot get the I/O addr 0x%x\n", + __func__, (unsigned int)res->start); + return -EBUSY; + } + + addr = ioremap(res->start, resource_size(res)); + if (!addr) { + pr_err("%s: ERROR: memory mapping failed\n", __func__); + ret = -ENOMEM; + goto out_release_region; + } + + ndev = alloc_etherdev(sizeof(struct stmmac_priv)); + if (!ndev) { + pr_err("%s: ERROR: allocating the device\n", __func__); + ret = -ENOMEM; + goto out_unmap; + } + + SET_NETDEV_DEV(ndev, &pdev->dev); + + /* Get the MAC information */ + ndev->irq = platform_get_irq_byname(pdev, "gmac_irq"); + if (ndev->irq == -ENXIO) { + pr_err("%s: ERROR: MAC IRQ configuration " + "information not found\n", __func__); + ret = -ENXIO; + goto out_free_ndev; + } + + priv = netdev_priv(ndev); + priv->device = &(pdev->dev); + priv->dev = ndev; + plat_dat = pdev->dev.platform_data; + + priv->plat = plat_dat; + + priv->ioaddr = addr; + + platform_set_drvdata(pdev, ndev); + + /* Set the I/O base addr */ + ndev->base_addr = (unsigned long)addr; + + /* Custom initialisation */ + if (priv->plat->init) { + ret = priv->plat->init(pdev); + if (unlikely(ret)) + goto out_free_ndev; + } + + /* MAC HW revice detection */ + ret = stmmac_mac_device_setup(ndev); + if (ret < 0) + goto out_plat_exit; + + /* Network Device Registration */ + ret = stmmac_probe(ndev); + if (ret < 0) + goto out_plat_exit; + + + /* 检查是否注册了一个phy到系统当中去,与stmmacphy_driver对应 */ + /* associate a PHY - it is provided by another platform bus */ + if (!driver_for_each_device + (&(stmmacphy_driver.driver), NULL, (void *)priv, + stmmac_associate_phy)) { + pr_err("No PHY device is associated with this MAC!\n"); + ret = -ENODEV; + goto out_unregister; + } + + pr_info("\t%s - (dev. name: %s - id: %d, IRQ #%d\n" + "\tIO base addr: 0x%p)\n", ndev->name, pdev->name, + pdev->id, ndev->irq, addr); + + /* MDIO bus Registration */ + pr_debug("\tMDIO bus (id: %d)...", priv->plat->bus_id); + ret = stmmac_mdio_register(ndev); + if (ret < 0) + goto out_unregister; + pr_debug("registered!\n"); + return 0; + +out_unregister: + unregister_netdev(ndev); +out_plat_exit: + if (priv->plat->exit) + priv->plat->exit(pdev); +out_free_ndev: + free_netdev(ndev); + platform_set_drvdata(pdev, NULL); +out_unmap: + iounmap(addr); +out_release_region: + release_mem_region(res->start, resource_size(res)); + + return ret; +} + +/** + * stmmac_dvr_remove + * @pdev: platform device pointer + * Description: this function resets the TX/RX processes, disables the MAC RX/TX + * changes the link status, releases the DMA descriptor rings, + * unregisters the MDIO bus and unmaps the allocated memory. + */ +static int stmmac_dvr_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct stmmac_priv *priv = netdev_priv(ndev); + struct resource *res; + + pr_info("%s:\n\tremoving driver", __func__); + + priv->hw->dma->stop_rx(priv->ioaddr); + priv->hw->dma->stop_tx(priv->ioaddr); + + stmmac_disable_mac(priv->ioaddr); + + netif_carrier_off(ndev); + + stmmac_mdio_unregister(ndev); + + if (priv->plat->exit) + priv->plat->exit(pdev); + + platform_set_drvdata(pdev, NULL); + unregister_netdev(ndev); + + iounmap((void *)priv->ioaddr); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + + free_netdev(ndev); + + return 0; +} + +static const struct dev_pm_ops stmmac_pm_ops; + +static struct platform_driver stmmac_driver = { + .probe = stmmac_dvr_probe, + .remove = stmmac_dvr_remove, + .driver = { + .name = STMMAC_RESOURCE_NAME, + .owner = THIS_MODULE, + .pm = &stmmac_pm_ops, + }, +}; + + +/* PLATFORM DEVICE */ +struct plat_stmmacenet_data xm550_gmac_platdata = { + .bus_id = 0, /* MAC挂在哪条总线上面,默认axi为0,需要和phy的bus_id保持一致, --0*/ + .pbl = 16, + .clk_csr = 0, /* mdio的时钟频率范围, 必须确保在1-2.5M之间,传输时钟为50M,设为--0000(存在一点问题?) */ + .has_gmac = 0, /* 千兆-1/百兆-0, 使用百兆,--0 */ + .enh_desc = 0, /* 增强形描述符-1/一般描述符-0, 使用一般描述符,--0 */ + .tx_coe = 0, /* gmac是否支持发送L4校验,简单起见暂不支持, --0 */ + .bugged_jumbo = 0, /* 超大帧,不支持千兆,暂不支持, --0 */ + .pmt = 0, /* 休眠省电模式,暂不支持, --0 */ + .fix_mac_speed = NULL, /* 调整速度,只支持自适应,速度在硬件上面决定, --NULL */ + .bus_setup = NULL, /* 暂时无用, --NULL */ + .init = NULL, /* 平台自定义初始化函数,不需要 ,NULL*/ + .exit = NULL, /* 不需要, --NULL */ + .custom_cfg = NULL, /* 不需要, --NULL */ + .bsp_priv = NULL /* 不需要, --NULL */ +}; + + + +static struct resource xm550_gmac_resource[] = { + [0] = { + .name = "gmac_addr", + .start = GMAC_BASE, + .end = GMAC_BASE + 0x10000 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "gmac_irq", + .start = GMAC_IRQ, + .end = GMAC_IRQ, + .flags = IORESOURCE_IRQ, + } + +}; +static void xm550_gmac_release(struct device *dev) +{ + return; +} +struct platform_device xm550_gmac = { + .name = STMMAC_RESOURCE_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(xm550_gmac_resource), + .resource = xm550_gmac_resource, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), /* 不然dma_alloc_coherent会失败 */ + .platform_data = &xm550_gmac_platdata, + .release = xm550_gmac_release, + } +}; + +struct plat_stmmacphy_data xm550_phy_platdata = { + 0, + 1, + 0, /* phy_mask */ + PHY_INTERFACE_MODE_RMII, + NULL, + NULL +}; + +static void xm550_phy_release(struct device *dev) +{ + return; +} +struct platform_device xm550_phy = { + .name = PHY_RESOURCE_NAME, + .id = -1 , + .dev = { + .platform_data = &xm550_phy_platdata, + .release = xm550_phy_release, + } +}; + + +/** + * stmmac_init_module - Entry point for the driver + * Description: This function is the entry point for the driver. + */ +static int __init stmmac_init_module(void) +{ + int ret; + + /* first phy,不然在gmac当中探测不到phy */ + ret = platform_device_register(&xm550_phy); + if (ret) { + pr_err("No MAC device registered!\n"); + return -ENODEV; + } + + if (platform_driver_register(&stmmacphy_driver)) { + pr_err("No PHY devices registered!\n"); + return -ENODEV; + } + + /* and mac */ + ret = platform_driver_register(&stmmac_driver); + if (ret) { + pr_err("No MAC driver registered!\n"); + return -ENODEV; + } + + ret = platform_device_register(&xm550_gmac); + if (ret) { + pr_err("No MAC device registered!\n"); + return -ENODEV; + } + + return ret; +} + +/** + * stmmac_cleanup_module - Cleanup routine for the driver + * Description: This function is the cleanup routine for the driver. + */ +static void __exit stmmac_cleanup_module(void) +{ + platform_driver_unregister(&stmmacphy_driver); + platform_device_unregister(&xm550_phy); + platform_driver_unregister(&stmmac_driver); + platform_device_unregister(&xm550_gmac); +} + +#ifndef MODULE +static int __init stmmac_cmdline_opt(char *str) +{ + char *opt; + + if (!str || !*str) + return -EINVAL; + while ((opt = strsep(&str, ",")) != NULL) { + if (!strncmp(opt, "debug:", 6)) + strict_strtoul(opt + 6, 0, (unsigned long *)&debug); + else if (!strncmp(opt, "phyaddr:", 8)) + strict_strtoul(opt + 8, 0, (unsigned long *)&phyaddr); + else if (!strncmp(opt, "dma_txsize:", 11)) + strict_strtoul(opt + 11, 0, + (unsigned long *)&dma_txsize); + else if (!strncmp(opt, "dma_rxsize:", 11)) + strict_strtoul(opt + 11, 0, + (unsigned long *)&dma_rxsize); + else if (!strncmp(opt, "buf_sz:", 7)) + strict_strtoul(opt + 7, 0, (unsigned long *)&buf_sz); + else if (!strncmp(opt, "tc:", 3)) + strict_strtoul(opt + 3, 0, (unsigned long *)&tc); + else if (!strncmp(opt, "watchdog:", 9)) + strict_strtoul(opt + 9, 0, (unsigned long *)&watchdog); + else if (!strncmp(opt, "flow_ctrl:", 10)) + strict_strtoul(opt + 10, 0, + (unsigned long *)&flow_ctrl); + else if (!strncmp(opt, "pause:", 6)) + strict_strtoul(opt + 6, 0, (unsigned long *)&pause); + } + return 0; +} + +/* 内核引导时,命令行当中是否包含stmmaceth参数,如果包含就执行后面的函数(被放到.init_setup区域) */ +__setup("stmmaceth=", stmmac_cmdline_opt); +#endif + +module_init(stmmac_init_module); +module_exit(stmmac_cleanup_module); + +MODULE_DESCRIPTION("XMMAC 10/100/1000 Ethernet driver"); +MODULE_AUTHOR("Giuseppe Cavallaro "); +MODULE_LICENSE("GPL"); diff -uarN a/drivers/net/xmmac/stmmac_mdio.c b/drivers/net/xmmac/stmmac_mdio.c --- a/drivers/net/xmmac/stmmac_mdio.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/stmmac_mdio.c 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,222 @@ +/******************************************************************************* + STMMAC Ethernet Driver -- MDIO bus implementation + Provides Bus interface for MII registers + + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Carl Shaw + Maintainer: Giuseppe Cavallaro +*******************************************************************************/ + +#include +#include +#include + +#include "stmmac.h" + +#define MII_BUSY 0x00000001 +#define MII_WRITE 0x00000002 + +/** + * stmmac_mdio_read + * @bus: points to the mii_bus structure + * @phyaddr: MII addr reg bits 15-11 + * @phyreg: MII addr reg bits 10-6 + * Description: it reads data from the MII register from within the phy device. + * For the 7111 GMAC, we must set the bit 0 in the MII address register while + * accessing the PHY registers. + * Fortunately, it seems this has no drawback for the 7109 MAC. + */ +static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) +{ + struct net_device *ndev = bus->priv; + struct stmmac_priv *priv = netdev_priv(ndev); + unsigned int mii_address = priv->hw->mii.addr; + unsigned int mii_data = priv->hw->mii.data; + + int data; + u16 regValue = (((phyaddr << 11) & (0x0000F800)) | + ((phyreg << 6) & (0x000007C0))); + regValue |= MII_BUSY | ((priv->plat->clk_csr & 7) << 2); + + //printk(KERN_EMERG"regValue:%x\n", regValue); + do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1); + writel(regValue, priv->ioaddr + mii_address); + do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1); + + /* Read the data from the MII data register */ + data = (int)readl(priv->ioaddr + mii_data); + + //printk(KERN_EMERG"data:%x\n", data); + + return data; +} + +/** + * stmmac_mdio_write + * @bus: points to the mii_bus structure + * @phyaddr: MII addr reg bits 15-11 + * @phyreg: MII addr reg bits 10-6 + * @phydata: phy data + * Description: it writes the data into the MII register from within the device. + */ +static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg, + u16 phydata) +{ + struct net_device *ndev = bus->priv; + struct stmmac_priv *priv = netdev_priv(ndev); + unsigned int mii_address = priv->hw->mii.addr; + unsigned int mii_data = priv->hw->mii.data; + + u16 value = + (((phyaddr << 11) & (0x0000F800)) | ((phyreg << 6) & (0x000007C0))) + | MII_WRITE; + + value |= MII_BUSY | ((priv->plat->clk_csr & 7) << 2); + + + /* Wait until any existing MII operation is complete */ + do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1); + + /* Set the MII address register to write */ + writel(phydata, priv->ioaddr + mii_data); + writel(value, priv->ioaddr + mii_address); + + /* Wait until any existing MII operation is complete */ + do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1); + + return 0; +} + +/** + * stmmac_mdio_reset + * @bus: points to the mii_bus structure + * Description: reset the MII bus + */ +static int stmmac_mdio_reset(struct mii_bus *bus) +{ + struct net_device *ndev = bus->priv; + struct stmmac_priv *priv = netdev_priv(ndev); + unsigned int mii_address = priv->hw->mii.addr; + + if (priv->phy_reset) { + pr_debug("stmmac_mdio_reset: calling phy_reset\n"); + priv->phy_reset(priv->plat->bsp_priv); + } + + /* This is a workaround for problems with the STE101P PHY. + * It doesn't complete its reset until at least one clock cycle + * on MDC, so perform a dummy mdio read. + */ + writel(0, priv->ioaddr + mii_address); + + return 0; +} + +/** + * stmmac_mdio_register + * @ndev: net device structure + * Description: it registers the MII bus + */ +int stmmac_mdio_register(struct net_device *ndev) +{ + int err = 0; + struct mii_bus *new_bus; + int *irqlist; + struct stmmac_priv *priv = netdev_priv(ndev); + int addr, found; + + new_bus = mdiobus_alloc(); + if (new_bus == NULL) + return -ENOMEM; + + irqlist = kzalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + if (irqlist == NULL) { + err = -ENOMEM; + goto irqlist_alloc_fail; + } + + /* Assign IRQ to phy at address phy_addr */ + if (priv->phy_addr != -1) + irqlist[priv->phy_addr] = priv->phy_irq; + + new_bus->name = "XMMMAC MII Bus"; + new_bus->read = &stmmac_mdio_read; + new_bus->write = &stmmac_mdio_write; + new_bus->reset = &stmmac_mdio_reset; + snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", priv->plat->bus_id); + new_bus->priv = ndev; + new_bus->irq = irqlist; + new_bus->phy_mask = priv->phy_mask; + new_bus->parent = priv->device; + err = mdiobus_register(new_bus); + if (err != 0) { + pr_err("%s: Cannot register as MDIO bus\n", new_bus->name); + goto bus_register_fail; + } + + priv->mii = new_bus; + + found = 0; + for (addr = 0; addr < 32; addr++) { + struct phy_device *phydev = new_bus->phy_map[addr]; + if (phydev) { + // printk(KERN_EMERG"find %d\n", addr); + if (priv->phy_addr == -1) { + priv->phy_addr = addr; + phydev->irq = priv->phy_irq; + irqlist[addr] = priv->phy_irq; + } + pr_info("%s: PHY ID %08x at %d IRQ %d (%s)%s\n", + ndev->name, phydev->phy_id, addr, + phydev->irq, dev_name(&phydev->dev), + (addr == priv->phy_addr) ? " active" : ""); + found = 1; + } + } + + if (!found) { + pr_warning("%s: No PHY found\n", ndev->name); + } else { + //printk(KERN_EMERG"Found\n"); + } + + return 0; +bus_register_fail: + kfree(irqlist); +irqlist_alloc_fail: + kfree(new_bus); + return err; +} + +/** + * stmmac_mdio_unregister + * @ndev: net device structure + * Description: it unregisters the MII bus + */ +int stmmac_mdio_unregister(struct net_device *ndev) +{ + struct stmmac_priv *priv = netdev_priv(ndev); + + mdiobus_unregister(priv->mii); + priv->mii->priv = NULL; + kfree(priv->mii); + + return 0; +} diff -uarN a/drivers/net/xmmac/stmmac_timer.c b/drivers/net/xmmac/stmmac_timer.c --- a/drivers/net/xmmac/stmmac_timer.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/stmmac_timer.c 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,134 @@ +/******************************************************************************* + STMMAC external timer support. + + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include +#include +#include "stmmac_timer.h" + +static void stmmac_timer_handler(void *data) +{ + struct net_device *dev = (struct net_device *)data; + + stmmac_schedule(dev); +} + +#define STMMAC_TIMER_MSG(timer, freq) \ +printk(KERN_INFO "stmmac_timer: %s Timer ON (freq %dHz)\n", timer, freq); + +#if defined(CONFIG_STMMAC_RTC_TIMER) +#include +static struct rtc_device *stmmac_rtc; +static rtc_task_t stmmac_task; + +static void stmmac_rtc_start(unsigned int new_freq) +{ + rtc_irq_set_freq(stmmac_rtc, &stmmac_task, new_freq); + rtc_irq_set_state(stmmac_rtc, &stmmac_task, 1); +} + +static void stmmac_rtc_stop(void) +{ + rtc_irq_set_state(stmmac_rtc, &stmmac_task, 0); +} + +int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm) +{ + stmmac_task.private_data = dev; + stmmac_task.func = stmmac_timer_handler; + + stmmac_rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); + if (stmmac_rtc == NULL) { + pr_err("open rtc device failed\n"); + return -ENODEV; + } + + rtc_irq_register(stmmac_rtc, &stmmac_task); + + /* Periodic mode is not supported */ + if ((rtc_irq_set_freq(stmmac_rtc, &stmmac_task, tm->freq) < 0)) { + pr_err("set periodic failed\n"); + rtc_irq_unregister(stmmac_rtc, &stmmac_task); + rtc_class_close(stmmac_rtc); + return -1; + } + + STMMAC_TIMER_MSG(CONFIG_RTC_HCTOSYS_DEVICE, tm->freq); + + tm->timer_start = stmmac_rtc_start; + tm->timer_stop = stmmac_rtc_stop; + + return 0; +} + +int stmmac_close_ext_timer(void) +{ + rtc_irq_set_state(stmmac_rtc, &stmmac_task, 0); + rtc_irq_unregister(stmmac_rtc, &stmmac_task); + rtc_class_close(stmmac_rtc); + return 0; +} + +#elif defined(CONFIG_STMMAC_TMU_TIMER) +#include +#define TMU_CHANNEL "tmu2_clk" +static struct clk *timer_clock; + +static void stmmac_tmu_start(unsigned int new_freq) +{ + clk_set_rate(timer_clock, new_freq); + clk_enable(timer_clock); +} + +static void stmmac_tmu_stop(void) +{ + clk_disable(timer_clock); +} + +int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm) +{ + timer_clock = clk_get(NULL, TMU_CHANNEL); + + if (timer_clock == NULL) + return -1; + + if (tmu2_register_user(stmmac_timer_handler, (void *)dev) < 0) { + timer_clock = NULL; + return -1; + } + + STMMAC_TIMER_MSG("TMU2", tm->freq); + tm->timer_start = stmmac_tmu_start; + tm->timer_stop = stmmac_tmu_stop; + + return 0; +} + +int stmmac_close_ext_timer(void) +{ + clk_disable(timer_clock); + tmu2_unregister_user(); + clk_put(timer_clock); + return 0; +} +#endif diff -uarN a/drivers/net/xmmac/stmmac_timer.h b/drivers/net/xmmac/stmmac_timer.h --- a/drivers/net/xmmac/stmmac_timer.h 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/net/xmmac/stmmac_timer.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,42 @@ +/******************************************************************************* + STMMAC external timer Header File. + + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +struct stmmac_timer { + void (*timer_start) (unsigned int new_freq); + void (*timer_stop) (void); + unsigned int freq; + unsigned int enable; +}; + +/* Open the HW timer device and return 0 in case of success */ +int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm); +/* Stop the timer and release it */ +int stmmac_close_ext_timer(void); +/* Function used for scheduling task within the stmmac */ +void stmmac_schedule(struct net_device *dev); + +#if defined(CONFIG_STMMAC_TMU_TIMER) +extern int tmu2_register_user(void *fnt, void *data); +extern void tmu2_unregister_user(void); +#endif diff -uarN a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c --- a/drivers/usb/gadget/composite.c 2016-08-28 13:19:20.000000000 +0300 +++ b/drivers/usb/gadget/composite.c 2019-02-14 05:41:45.000000000 +0300 @@ -260,10 +260,10 @@ spin_lock_irqsave(&cdev->lock, flags); - if (cdev->deactivations == 0) + if (cdev->deactivations == 0) { status = usb_gadget_disconnect(cdev->gadget); - if (status == 0) cdev->deactivations++; + } spin_unlock_irqrestore(&cdev->lock, flags); return status; diff -uarN a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c --- a/drivers/usb/gadget/configfs.c 2016-08-28 13:19:20.000000000 +0300 +++ b/drivers/usb/gadget/configfs.c 2019-02-14 05:41:45.000000000 +0300 @@ -240,7 +240,7 @@ const char *page, size_t len) { char *name; - int ret; + int ret = -1; name = kstrdup(page, GFP_KERNEL); if (!name) @@ -259,10 +259,15 @@ ret = -EBUSY; goto err; } +#if 0 ret = udc_attach_driver(name, &gi->composite.gadget_driver); if (ret) goto err; gi->udc_name = name; +#else + goto err; +#endif + } mutex_unlock(&gi->lock); return len; diff -uarN a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c --- a/drivers/usb/gadget/f_uvc.c 2016-08-28 13:19:20.000000000 +0300 +++ b/drivers/usb/gadget/f_uvc.c 2019-02-14 05:41:45.000000000 +0300 @@ -33,7 +33,7 @@ /*-------------------------------------------------------------------------*/ /* module parameters specific to the Video streaming endpoint */ -static unsigned int streaming_interval = 1; +static unsigned int streaming_interval = 2; module_param(streaming_interval, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(streaming_interval, "1 - 16"); @@ -55,7 +55,7 @@ #define UVC_STRING_STREAMING_IDX 1 static struct usb_string uvc_en_us_strings[] = { - [UVC_STRING_CONTROL_IDX].s = "UVC Camera", + [UVC_STRING_CONTROL_IDX].s = "XM Camera", [UVC_STRING_STREAMING_IDX].s = "Video Streaming", { } }; @@ -616,6 +616,7 @@ max_packet_mult = 3; max_packet_size = streaming_maxpacket / 3; } + INFO(cdev, "streaming_interval=%u, streaming_maxpacket=%u streaming_maxburst=%u\n", streaming_interval, streaming_maxpacket, streaming_maxburst); uvc_fs_streaming_ep.wMaxPacketSize = min(streaming_maxpacket, 1023U); uvc_fs_streaming_ep.bInterval = streaming_interval; @@ -655,19 +656,25 @@ uvc->video.ep = ep; ep->driver_data = uvc; + //printk("ep address %d\n", uvc->video.ep->address); + uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address; uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address; uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address; /* Allocate interface IDs. */ - if ((ret = usb_interface_id(c, f)) < 0) + if ((ret = usb_interface_id(c, f)) < 0) { + //INFO(cdev, "usb_interface_id err\n"); goto error; + } uvc_iad.bFirstInterface = ret; uvc_control_intf.bInterfaceNumber = ret; uvc->control_intf = ret; - if ((ret = usb_interface_id(c, f)) < 0) + if ((ret = usb_interface_id(c, f)) < 0) { + //INFO(cdev, "2 usb_interface_id err\n"); goto error; + } uvc_streaming_intf_alt0.bInterfaceNumber = ret; uvc_streaming_intf_alt1.bInterfaceNumber = ret; uvc->streaming_intf = ret; @@ -683,6 +690,7 @@ uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL); uvc->control_buf = kmalloc(UVC_MAX_REQUEST_SIZE, GFP_KERNEL); if (uvc->control_req == NULL || uvc->control_buf == NULL) { + INFO(cdev, "ENOMEM\n"); ret = -ENOMEM; goto error; } @@ -694,13 +702,17 @@ /* Avoid letting this gadget enumerate until the userspace server is * active. */ - if ((ret = usb_function_deactivate(f)) < 0) + if ((ret = usb_function_deactivate(f)) < 0) { + INFO(cdev, "usb_function_deactivate err\n"); goto error; + } /* Initialise video. */ ret = uvc_video_init(&uvc->video); - if (ret < 0) + if (ret < 0) { + INFO(cdev, "uvc_video_init err\n"); goto error; + } /* Register a V4L2 device. */ ret = uvc_register_video(uvc); @@ -709,6 +721,7 @@ goto error; } + return 0; error: diff -uarN a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c --- a/drivers/usb/gadget/uvc_queue.c 2016-08-28 13:19:20.000000000 +0300 +++ b/drivers/usb/gadget/uvc_queue.c 2019-02-14 05:41:45.000000000 +0300 @@ -120,6 +120,10 @@ queue->queue.buf_struct_size = sizeof(struct uvc_buffer); queue->queue.ops = &uvc_queue_qops; queue->queue.mem_ops = &vb2_vmalloc_memops; + + queue->queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC + | V4L2_BUF_FLAG_TIMESTAMP_COPY; + ret = vb2_queue_init(&queue->queue); if (ret) return ret; diff -uarN a/drivers/usb/gadget/uvc_video.c b/drivers/usb/gadget/uvc_video.c --- a/drivers/usb/gadget/uvc_video.c 2016-08-28 13:19:20.000000000 +0300 +++ b/drivers/usb/gadget/uvc_video.c 2019-02-14 05:41:45.000000000 +0300 @@ -185,12 +185,14 @@ spin_lock_irqsave(&video->queue.irqlock, flags); buf = uvc_queue_head(&video->queue); if (buf == NULL) { - spin_unlock_irqrestore(&video->queue.irqlock, flags); - goto requeue; + //spin_unlock_irqrestore(&video->queue.irqlock, flags); + req->length = 0; + goto tran_zero; } video->encode(req, video, buf); +tran_zero: if ((ret = usb_ep_queue(ep, req, GFP_ATOMIC)) < 0) { printk(KERN_INFO "Failed to queue request (%d).\n", ret); usb_ep_set_halt(ep); diff -uarN a/drivers/usb/gadget/webcam.c b/drivers/usb/gadget/webcam.c --- a/drivers/usb/gadget/webcam.c 2016-08-28 13:19:20.000000000 +0300 +++ b/drivers/usb/gadget/webcam.c 2019-02-14 05:41:45.000000000 +0300 @@ -37,8 +37,22 @@ #define WEBCAM_PRODUCT_ID 0x0102 /* Webcam A/V gadget */ #define WEBCAM_DEVICE_BCD 0x0010 /* 0.10 */ -static char webcam_vendor_label[] = "Linux Foundation"; -static char webcam_product_label[] = "Webcam gadget"; +/* + * 4.1.1 Extension Unit GUIDs + * Codec (H.264) Control {A29E7641-DE04-47E3-8B2B-F4341AFF003B} + */ +#define GUID_UVCX_H264_XU {0x41, 0x76, 0x9E, 0xA2, 0x04, 0xDE, 0xE3, 0x47, \ + 0x8B, 0x2B, 0xF4, 0x34, 0x1A, 0xFF, 0x00, 0x3B} +/* + * 4.1.2 H.264 Streams GUIDs + * MEDIASUBTYPE_H264 {34363248-0000-0010-0x8000-00aa00389b71} + */ +#define UVC_GUID_FORMAT_H264 {0x48, 0x32, 0x36, 0x34, 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} + + +static char webcam_vendor_label[] = "HZXM"; +static char webcam_product_label[] = "XM530"; static char webcam_config_label[] = "Video"; /* string IDs are assigned dynamically */ @@ -86,10 +100,10 @@ .bLength = UVC_DT_HEADER_SIZE(1), .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = UVC_VC_HEADER, - .bcdUVC = cpu_to_le16(0x0100), + .bcdUVC = cpu_to_le16(0x0110), .wTotalLength = 0, /* dynamic */ .dwClockFrequency = cpu_to_le32(48000000), - .bInCollection = 0, /* dynamic */ + .bInCollection = 1, /* dynamic */ .baInterfaceNr[0] = 0, /* dynamic */ }; @@ -110,8 +124,11 @@ .bmControls[2] = 0, }; -static const struct uvc_processing_unit_descriptor uvc_processing = { - .bLength = UVC_DT_PROCESSING_UNIT_SIZE(2), +DECLARE_UVC_PROCESSING_UNIT_DESCRIPTOR(2); + +//static const struct uvc_processing_unit_descriptor uvc_processing = { +static const struct UVC_PROCESSING_UNIT_DESCRIPTOR(2) uvc_processing = { + .bLength = sizeof(uvc_processing), .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = UVC_VC_PROCESSING_UNIT, .bUnitID = 2, @@ -121,6 +138,24 @@ .bmControls[0] = 1, .bmControls[1] = 0, .iProcessing = 0, + .bmVideoStandards = 0, +}; + +DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(1, 2); + +static const struct UVC_EXTENSION_UNIT_DESCRIPTOR(1, 2) uvc_xu_h264_desc = { + .bLength = UVC_DT_EXTENSION_UNIT_SIZE(1, 2), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = UVC_VC_EXTENSION_UNIT, + .bUnitID = 10, + .guidExtensionCode = GUID_UVCX_H264_XU, + .bNumControls = 15, + .bNrInPins = 1, + .baSourceID[0] = 2, + .bControlSize = 2, + .bmControls[0] = 0xff, + .bmControls[1] = 0xff, + .iExtension = 0, }; static const struct uvc_output_terminal_descriptor uvc_output_terminal = { @@ -130,12 +165,12 @@ .bTerminalID = 3, .wTerminalType = cpu_to_le16(0x0101), .bAssocTerminal = 0, - .bSourceID = 2, + .bSourceID = 10, .iTerminal = 0, }; -DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(1, 2); +DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(1, 2); static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = { .bLength = UVC_DT_INPUT_HEADER_SIZE(1, 2), .bDescriptorType = USB_DT_CS_INTERFACE, @@ -150,9 +185,10 @@ .bTriggerUsage = 0, .bControlSize = 1, .bmaControls[0][0] = 0, - .bmaControls[1][0] = 4, + .bmaControls[1][0] = 0, }; +#if 0 static const struct uvc_format_uncompressed uvc_format_yuv = { .bLength = UVC_DT_FORMAT_UNCOMPRESSED_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -206,15 +242,16 @@ .bFrameIntervalType = 1, .dwFrameInterval[0] = cpu_to_le32(5000000), }; +#endif static const struct uvc_format_mjpeg uvc_format_mjpg = { .bLength = UVC_DT_FORMAT_MJPEG_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = UVC_VS_FORMAT_MJPEG, - .bFormatIndex = 2, - .bNumFrameDescriptors = 2, + .bFormatIndex = 1, + .bNumFrameDescriptors = 3, .bmFlags = 0, - .bDefaultFrameIndex = 1, + .bDefaultFrameIndex = 3, .bAspectRatioX = 0, .bAspectRatioY = 0, .bmInterfaceFlags = 0, @@ -234,12 +271,12 @@ .wHeight = cpu_to_le16(360), .dwMinBitRate = cpu_to_le32(18432000), .dwMaxBitRate = cpu_to_le32(55296000), - .dwMaxVideoFrameBufferSize = cpu_to_le32(460800), - .dwDefaultFrameInterval = cpu_to_le32(666666), + .dwMaxVideoFrameBufferSize = cpu_to_le32(345600), + .dwDefaultFrameInterval = cpu_to_le32(333333), .bFrameIntervalType = 3, - .dwFrameInterval[0] = cpu_to_le32(666666), - .dwFrameInterval[1] = cpu_to_le32(1000000), - .dwFrameInterval[2] = cpu_to_le32(5000000), + .dwFrameInterval[0] = cpu_to_le32(333333), + .dwFrameInterval[1] = cpu_to_le32(500000), + .dwFrameInterval[2] = cpu_to_le32(2500000), }; static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = { @@ -252,10 +289,92 @@ .wHeight = cpu_to_le16(720), .dwMinBitRate = cpu_to_le32(29491200), .dwMaxBitRate = cpu_to_le32(29491200), - .dwMaxVideoFrameBufferSize = cpu_to_le32(1843200), - .dwDefaultFrameInterval = cpu_to_le32(5000000), + .dwMaxVideoFrameBufferSize = cpu_to_le32(1382400), + .dwDefaultFrameInterval = cpu_to_le32(333333), .bFrameIntervalType = 1, - .dwFrameInterval[0] = cpu_to_le32(5000000), + .dwFrameInterval[0] = cpu_to_le32(333333), +}; + +static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_1080p = { + .bLength = UVC_DT_FRAME_MJPEG_SIZE(1), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = UVC_VS_FRAME_MJPEG, + .bFrameIndex = 3, + .bmCapabilities = 0, + .wWidth = cpu_to_le16(1920), + .wHeight = cpu_to_le16(1080), + .dwMinBitRate = cpu_to_le32(58982400), + .dwMaxBitRate = cpu_to_le32(58982400), + .dwMaxVideoFrameBufferSize = cpu_to_le32(3110400), + .dwDefaultFrameInterval = cpu_to_le32(333333), + .bFrameIntervalType = 1, + .dwFrameInterval[0] = cpu_to_le32(333333), +}; + +static const struct uvc_format_h264_base uvc_format_h264_base = { + .bLength = sizeof(uvc_format_h264_base), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = UVC_VS_FORMAT_FRAME_BASED, + .bFormatIndex = 2, + .bNumFrameDescriptors = 3, + .guidFormat = UVC_GUID_FORMAT_H264, + .bBitsPerPixel = 16, + .bDefaultFrameIndex = 1, + .bAspectRatioX = 0, + .bAspectRatioY = 0, + .bmInterfaceFlags = 0, + .bCopyProtect = 0, + .bVariableSize = 1, +}; + +DECLARE_UVC_FRAME_H264_BASE(1); + +static const struct UVC_FRAME_H264_BASE(1) uvc_frame_h264_360p = { + .bLength = UVC_DT_FRAME_MJPEG_SIZE(1), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = UVC_VS_FRAME_FRAME_BASED, + .bFrameIndex = 1, + .bmCapabilities = 0, + .wWidth = cpu_to_le16(640), + .wHeight = cpu_to_le16(360), + .dwMinBitRate = cpu_to_le32(18432000), + .dwMaxBitRate = cpu_to_le32(18432000), + .dwDefaultFrameInterval = cpu_to_le32(333333), + .bFrameIntervalType = 1, + .dwBytesPerLine = 0, + .dwFrameInterval[0] = cpu_to_le32(333333), +}; + +static const struct UVC_FRAME_H264_BASE(1) uvc_frame_h264_720p = { + .bLength = UVC_DT_FRAME_MJPEG_SIZE(1), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = UVC_VS_FRAME_FRAME_BASED, + .bFrameIndex = 2, + .bmCapabilities = 0, + .wWidth = cpu_to_le16(1280), + .wHeight = cpu_to_le16(720), + .dwMinBitRate = cpu_to_le32(29491200), + .dwMaxBitRate = cpu_to_le32(29491200), + .dwDefaultFrameInterval = cpu_to_le32(333333), + .bFrameIntervalType = 1, + .dwBytesPerLine = 0, + .dwFrameInterval[0] = cpu_to_le32(333333), +}; + +static const struct UVC_FRAME_H264_BASE(1) uvc_frame_h264_1080p = { + .bLength = UVC_DT_FRAME_MJPEG_SIZE(1), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = UVC_VS_FRAME_FRAME_BASED, + .bFrameIndex = 3, + .bmCapabilities = 0, + .wWidth = cpu_to_le16(1920), + .wHeight = cpu_to_le16(1080), + .dwMinBitRate = cpu_to_le32(58982400), + .dwMaxBitRate = cpu_to_le32(58982400), + .dwDefaultFrameInterval = cpu_to_le32(333333), + .bFrameIntervalType = 1, + .dwBytesPerLine = 0, + .dwFrameInterval[0] = cpu_to_le32(333333), }; static const struct uvc_color_matching_descriptor uvc_color_matching = { @@ -271,6 +390,7 @@ (const struct uvc_descriptor_header *) &uvc_control_header, (const struct uvc_descriptor_header *) &uvc_camera_terminal, (const struct uvc_descriptor_header *) &uvc_processing, + (const struct uvc_descriptor_header *) &uvc_xu_h264_desc, (const struct uvc_descriptor_header *) &uvc_output_terminal, NULL, }; @@ -279,42 +399,70 @@ (const struct uvc_descriptor_header *) &uvc_control_header, (const struct uvc_descriptor_header *) &uvc_camera_terminal, (const struct uvc_descriptor_header *) &uvc_processing, + (const struct uvc_descriptor_header *) &uvc_xu_h264_desc, (const struct uvc_descriptor_header *) &uvc_output_terminal, NULL, }; static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = { (const struct uvc_descriptor_header *) &uvc_input_header, +#if 0 (const struct uvc_descriptor_header *) &uvc_format_yuv, (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, +#endif (const struct uvc_descriptor_header *) &uvc_format_mjpg, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, + (const struct uvc_descriptor_header *) &uvc_frame_mjpg_1080p, + + (const struct uvc_descriptor_header *) &uvc_format_h264_base, + (const struct uvc_descriptor_header *) &uvc_frame_h264_360p, + (const struct uvc_descriptor_header *) &uvc_frame_h264_720p, + (const struct uvc_descriptor_header *) &uvc_frame_h264_1080p, + (const struct uvc_descriptor_header *) &uvc_color_matching, NULL, }; static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = { (const struct uvc_descriptor_header *) &uvc_input_header, +#if 0 (const struct uvc_descriptor_header *) &uvc_format_yuv, (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, +#endif (const struct uvc_descriptor_header *) &uvc_format_mjpg, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, + (const struct uvc_descriptor_header *) &uvc_frame_mjpg_1080p, + + (const struct uvc_descriptor_header *) &uvc_format_h264_base, + (const struct uvc_descriptor_header *) &uvc_frame_h264_360p, + (const struct uvc_descriptor_header *) &uvc_frame_h264_720p, + (const struct uvc_descriptor_header *) &uvc_frame_h264_1080p, + (const struct uvc_descriptor_header *) &uvc_color_matching, NULL, }; static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = { (const struct uvc_descriptor_header *) &uvc_input_header, +#if 0 (const struct uvc_descriptor_header *) &uvc_format_yuv, (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, +#endif (const struct uvc_descriptor_header *) &uvc_format_mjpg, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, + (const struct uvc_descriptor_header *) &uvc_frame_mjpg_1080p, + + (const struct uvc_descriptor_header *) &uvc_format_h264_base, + (const struct uvc_descriptor_header *) &uvc_frame_h264_360p, + (const struct uvc_descriptor_header *) &uvc_frame_h264_720p, + (const struct uvc_descriptor_header *) &uvc_frame_h264_1080p, + (const struct uvc_descriptor_header *) &uvc_color_matching, NULL, }; @@ -385,7 +533,7 @@ .name = "g_webcam", .dev = &webcam_device_descriptor, .strings = webcam_device_strings, - .max_speed = USB_SPEED_SUPER, + .max_speed = USB_SPEED_HIGH/*USB_SPEED_SUPER*/, .bind = webcam_bind, .unbind = webcam_unbind, }; diff -uarN a/include/linux/jiffies.h b/include/linux/jiffies.h --- a/include/linux/jiffies.h 2016-08-28 13:19:20.000000000 +0300 +++ b/include/linux/jiffies.h 2018-11-21 06:44:38.000000000 +0300 @@ -159,7 +159,10 @@ * Have the 32 bit jiffies value wrap 5 minutes after boot * so jiffies wrap bugs show up earlier. */ -#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ)) +/*#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ))*/ +/*为了兼容应用程序*/ +#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (0)) + /* * Change timeval to jiffies, trying to avoid the diff -uarN a/include/linux/mmc/arasan_plat.h b/include/linux/mmc/arasan_plat.h --- a/include/linux/mmc/arasan_plat.h 1970-01-01 03:00:00.000000000 +0300 +++ b/include/linux/mmc/arasan_plat.h 2018-11-21 06:44:38.000000000 +0300 @@ -0,0 +1,39 @@ +/* + * + * include/linux/mmc/arsan_plat.h + * + * platform data for the Arasan MMC/SD/SDI HC driver + * + * + * 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. + * + */ + +#ifndef __ARASAN_PLAT_H__ +#define __ARASAN_PLAT_H__ + +typedef void (*func_t)(void); +struct arasan_platform_data { + unsigned int need_poll; + unsigned int need_detect; + unsigned int use_pio; + + unsigned int card_irq; /* sd卡不能处理card中断 */ + unsigned int auto_cmd12; /* 多块传输时, sdio不能自动发送cmd12 + 而sd则需要自动发送cmd12;如果sdio自动 + 发送cmd12,则wifi不会响应,引起响应超时 + */ + unsigned int sdio_4bit_data; + + func_t p_powerup; + +}; + +static inline int arasan_claim_resource(struct platform_device *pdev) +{ + return 0; +} + +#endif diff -uarN a/include/linux/stmmac.h b/include/linux/stmmac.h --- a/include/linux/stmmac.h 2016-08-28 13:19:20.000000000 +0300 +++ b/include/linux/stmmac.h 2018-11-21 06:44:38.000000000 +0300 @@ -20,8 +20,8 @@ The full GNU General Public License is included in this distribution in the file called "COPYING". - Author: Giuseppe Cavallaro -*******************************************************************************/ +Author: Giuseppe Cavallaro + *******************************************************************************/ #ifndef __STMMAC_PLATFORM_DATA #define __STMMAC_PLATFORM_DATA @@ -70,47 +70,34 @@ #define DMA_AXI_BLEN_128 (1 << 6) #define DMA_AXI_BLEN_256 (1 << 7) #define DMA_AXI_BLEN_ALL (DMA_AXI_BLEN_4 | DMA_AXI_BLEN_8 | DMA_AXI_BLEN_16 \ - | DMA_AXI_BLEN_32 | DMA_AXI_BLEN_64 \ - | DMA_AXI_BLEN_128 | DMA_AXI_BLEN_256) + | DMA_AXI_BLEN_32 | DMA_AXI_BLEN_64 \ + | DMA_AXI_BLEN_128 | DMA_AXI_BLEN_256) /* Platfrom data for platform device structure's platform_data field */ - -struct stmmac_mdio_bus_data { - int (*phy_reset)(void *priv); - unsigned int phy_mask; - int *irqs; - int probed_phy_irq; +struct plat_stmmacenet_data { + int bus_id; + int pbl; + int clk_csr; + int has_gmac; + int enh_desc; + int tx_coe; + int bugged_jumbo; + int pmt; + void (*fix_mac_speed)(void *priv, unsigned int speed); + void (*bus_setup)(void __iomem *ioaddr); + int (*init)(struct platform_device *pdev); + void (*exit)(struct platform_device *pdev); + void *custom_cfg; + void *bsp_priv; }; -struct stmmac_dma_cfg { - int pbl; - int fixed_burst; - int mixed_burst; - int burst_len; +struct plat_stmmacphy_data { + int bus_id; + int phy_addr; + unsigned int phy_mask; + int interface; + int (*phy_reset)(void *priv); + void *priv; }; -struct plat_stmmacenet_data { - char *phy_bus_name; - int bus_id; - int phy_addr; - int interface; - struct stmmac_mdio_bus_data *mdio_bus_data; - struct stmmac_dma_cfg *dma_cfg; - int clk_csr; - int has_gmac; - int enh_desc; - int tx_coe; - int rx_coe; - int bugged_jumbo; - int pmt; - int force_sf_dma_mode; - int riwt_off; - void (*fix_mac_speed)(void *priv, unsigned int speed); - void (*bus_setup)(void __iomem *ioaddr); - int (*init)(struct platform_device *pdev); - void (*exit)(struct platform_device *pdev); - void *custom_cfg; - void *custom_data; - void *bsp_priv; -}; #endif diff -uarN a/include/uapi/linux/netfilter/xt_CONNMARK.h b/include/uapi/linux/netfilter/xt_CONNMARK.h --- a/include/uapi/linux/netfilter/xt_CONNMARK.h 2016-08-28 13:19:20.000000000 +0300 +++ b/include/uapi/linux/netfilter/xt_CONNMARK.h 2018-11-21 06:44:38.000000000 +0300 @@ -1,6 +1,31 @@ -#ifndef _XT_CONNMARK_H_target -#define _XT_CONNMARK_H_target +#ifndef _XT_CONNMARK_H +#define _XT_CONNMARK_H -#include +#include -#endif /*_XT_CONNMARK_H_target*/ +/* Copyright (C) 2002,2004 MARA Systems AB + * by Henrik Nordstrom + * + * 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. + */ + +enum { + XT_CONNMARK_SET = 0, + XT_CONNMARK_SAVE, + XT_CONNMARK_RESTORE +}; + +struct xt_connmark_tginfo1 { + __u32 ctmark, ctmask, nfmask; + __u8 mode; +}; + +struct xt_connmark_mtinfo1 { + __u32 mark, mask; + __u8 invert; +}; + +#endif /*_XT_CONNMARK_H*/ diff -uarN a/include/uapi/linux/netfilter/xt_DSCP.h b/include/uapi/linux/netfilter/xt_DSCP.h --- a/include/uapi/linux/netfilter/xt_DSCP.h 2016-08-28 13:19:20.000000000 +0300 +++ b/include/uapi/linux/netfilter/xt_DSCP.h 2018-11-21 06:44:38.000000000 +0300 @@ -1,26 +1,31 @@ -/* x_tables module for setting the IPv4/IPv6 DSCP field +/* x_tables module for matching the IPv4/IPv6 DSCP field * * (C) 2002 Harald Welte - * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh * This software is distributed under GNU GPL v2, 1991 * * See RFC2474 for a description of the DSCP field within the IP Header. * - * xt_DSCP.h,v 1.7 2002/03/14 12:03:13 laforge Exp + * xt_dscp.h,v 1.3 2002/08/05 19:00:21 laforge Exp */ -#ifndef _XT_DSCP_TARGET_H -#define _XT_DSCP_TARGET_H -#include +#ifndef _XT_DSCP_H +#define _XT_DSCP_H + #include -/* target info */ -struct xt_DSCP_info { +#define XT_DSCP_MASK 0xfc /* 11111100 */ +#define XT_DSCP_SHIFT 2 +#define XT_DSCP_MAX 0x3f /* 00111111 */ + +/* match info */ +struct xt_dscp_info { __u8 dscp; + __u8 invert; }; -struct xt_tos_target_info { - __u8 tos_value; +struct xt_tos_match_info { __u8 tos_mask; + __u8 tos_value; + __u8 invert; }; -#endif /* _XT_DSCP_TARGET_H */ +#endif /* _XT_DSCP_H */ diff -uarN a/include/uapi/linux/netfilter/xt_MARK.h b/include/uapi/linux/netfilter/xt_MARK.h --- a/include/uapi/linux/netfilter/xt_MARK.h 2016-08-28 13:19:20.000000000 +0300 +++ b/include/uapi/linux/netfilter/xt_MARK.h 2018-11-21 06:44:38.000000000 +0300 @@ -1,6 +1,15 @@ -#ifndef _XT_MARK_H_target -#define _XT_MARK_H_target +#ifndef _XT_MARK_H +#define _XT_MARK_H -#include +#include -#endif /*_XT_MARK_H_target */ +struct xt_mark_tginfo2 { + __u32 mark, mask; +}; + +struct xt_mark_mtinfo1 { + __u32 mark, mask; + __u8 invert; +}; + +#endif /*_XT_MARK_H*/ diff -uarN a/include/uapi/linux/netfilter/xt_RATEEST.h b/include/uapi/linux/netfilter/xt_RATEEST.h --- a/include/uapi/linux/netfilter/xt_RATEEST.h 2016-08-28 13:19:20.000000000 +0300 +++ b/include/uapi/linux/netfilter/xt_RATEEST.h 2018-11-21 06:44:38.000000000 +0300 @@ -1,15 +1,37 @@ -#ifndef _XT_RATEEST_TARGET_H -#define _XT_RATEEST_TARGET_H +#ifndef _XT_RATEEST_MATCH_H +#define _XT_RATEEST_MATCH_H #include -struct xt_rateest_target_info { - char name[IFNAMSIZ]; - __s8 interval; - __u8 ewma_log; +enum xt_rateest_match_flags { + XT_RATEEST_MATCH_INVERT = 1<<0, + XT_RATEEST_MATCH_ABS = 1<<1, + XT_RATEEST_MATCH_REL = 1<<2, + XT_RATEEST_MATCH_DELTA = 1<<3, + XT_RATEEST_MATCH_BPS = 1<<4, + XT_RATEEST_MATCH_PPS = 1<<5, +}; + +enum xt_rateest_match_mode { + XT_RATEEST_MATCH_NONE, + XT_RATEEST_MATCH_EQ, + XT_RATEEST_MATCH_LT, + XT_RATEEST_MATCH_GT, +}; + +struct xt_rateest_match_info { + char name1[IFNAMSIZ]; + char name2[IFNAMSIZ]; + __u16 flags; + __u16 mode; + __u32 bps1; + __u32 pps1; + __u32 bps2; + __u32 pps2; /* Used internally by the kernel */ - struct xt_rateest *est __attribute__((aligned(8))); + struct xt_rateest *est1 __attribute__((aligned(8))); + struct xt_rateest *est2 __attribute__((aligned(8))); }; -#endif /* _XT_RATEEST_TARGET_H */ +#endif /* _XT_RATEEST_MATCH_H */ diff -uarN a/include/uapi/linux/netfilter/xt_TCPMSS.h b/include/uapi/linux/netfilter/xt_TCPMSS.h --- a/include/uapi/linux/netfilter/xt_TCPMSS.h 2016-08-28 13:19:20.000000000 +0300 +++ b/include/uapi/linux/netfilter/xt_TCPMSS.h 2018-11-21 06:44:38.000000000 +0300 @@ -1,12 +1,11 @@ -#ifndef _XT_TCPMSS_H -#define _XT_TCPMSS_H +#ifndef _XT_TCPMSS_MATCH_H +#define _XT_TCPMSS_MATCH_H #include -struct xt_tcpmss_info { - __u16 mss; +struct xt_tcpmss_match_info { + __u16 mss_min, mss_max; + __u8 invert; }; -#define XT_TCPMSS_CLAMP_PMTU 0xffff - -#endif /* _XT_TCPMSS_H */ +#endif /*_XT_TCPMSS_MATCH_H*/ diff -uarN a/include/uapi/linux/netfilter_ipv4/ipt_ECN.h b/include/uapi/linux/netfilter_ipv4/ipt_ECN.h --- a/include/uapi/linux/netfilter_ipv4/ipt_ECN.h 2016-08-28 13:19:20.000000000 +0300 +++ b/include/uapi/linux/netfilter_ipv4/ipt_ECN.h 2018-11-21 06:44:38.000000000 +0300 @@ -1,33 +1,15 @@ -/* Header file for iptables ipt_ECN target - * - * (C) 2002 by Harald Welte - * - * This software is distributed under GNU GPL v2, 1991 - * - * ipt_ECN.h,v 1.3 2002/05/29 12:17:40 laforge Exp -*/ -#ifndef _IPT_ECN_TARGET_H -#define _IPT_ECN_TARGET_H +#ifndef _IPT_ECN_H +#define _IPT_ECN_H -#include -#include +#include +#define ipt_ecn_info xt_ecn_info -#define IPT_ECN_IP_MASK (~XT_DSCP_MASK) - -#define IPT_ECN_OP_SET_IP 0x01 /* set ECN bits of IPv4 header */ -#define IPT_ECN_OP_SET_ECE 0x10 /* set ECE bit of TCP header */ -#define IPT_ECN_OP_SET_CWR 0x20 /* set CWR bit of TCP header */ - -#define IPT_ECN_OP_MASK 0xce - -struct ipt_ECN_info { - __u8 operation; /* bitset of operations */ - __u8 ip_ect; /* ECT codepoint of IPv4 header, pre-shifted */ - union { - struct { - __u8 ece:1, cwr:1; /* TCP ECT bits */ - } tcp; - } proto; +enum { + IPT_ECN_IP_MASK = XT_ECN_IP_MASK, + IPT_ECN_OP_MATCH_IP = XT_ECN_OP_MATCH_IP, + IPT_ECN_OP_MATCH_ECE = XT_ECN_OP_MATCH_ECE, + IPT_ECN_OP_MATCH_CWR = XT_ECN_OP_MATCH_CWR, + IPT_ECN_OP_MATCH_MASK = XT_ECN_OP_MATCH_MASK, }; -#endif /* _IPT_ECN_TARGET_H */ +#endif /* IPT_ECN_H */ diff -uarN a/include/uapi/linux/netfilter_ipv4/ipt_TTL.h b/include/uapi/linux/netfilter_ipv4/ipt_TTL.h --- a/include/uapi/linux/netfilter_ipv4/ipt_TTL.h 2016-08-28 13:19:20.000000000 +0300 +++ b/include/uapi/linux/netfilter_ipv4/ipt_TTL.h 2018-11-21 06:44:38.000000000 +0300 @@ -1,5 +1,5 @@ -/* TTL modification module for IP tables - * (C) 2000 by Harald Welte */ +/* IP tables module for matching the value of the TTL + * (C) 2000 by Harald Welte */ #ifndef _IPT_TTL_H #define _IPT_TTL_H @@ -7,14 +7,14 @@ #include enum { - IPT_TTL_SET = 0, - IPT_TTL_INC, - IPT_TTL_DEC + IPT_TTL_EQ = 0, /* equals */ + IPT_TTL_NE, /* not equals */ + IPT_TTL_LT, /* less than */ + IPT_TTL_GT, /* greater than */ }; -#define IPT_TTL_MAXMODE IPT_TTL_DEC -struct ipt_TTL_info { +struct ipt_ttl_info { __u8 mode; __u8 ttl; }; diff -uarN a/include/uapi/linux/netfilter_ipv6/ip6t_HL.h b/include/uapi/linux/netfilter_ipv6/ip6t_HL.h --- a/include/uapi/linux/netfilter_ipv6/ip6t_HL.h 2016-08-28 13:19:20.000000000 +0300 +++ b/include/uapi/linux/netfilter_ipv6/ip6t_HL.h 2018-11-21 06:44:38.000000000 +0300 @@ -1,6 +1,6 @@ -/* Hop Limit modification module for ip6tables +/* ip6tables module for matching the Hop Limit value * Maciej Soltysiak - * Based on HW's TTL module */ + * Based on HW's ttl module */ #ifndef _IP6T_HL_H #define _IP6T_HL_H @@ -8,14 +8,14 @@ #include enum { - IP6T_HL_SET = 0, - IP6T_HL_INC, - IP6T_HL_DEC + IP6T_HL_EQ = 0, /* equals */ + IP6T_HL_NE, /* not equals */ + IP6T_HL_LT, /* less than */ + IP6T_HL_GT, /* greater than */ }; -#define IP6T_HL_MAXMODE IP6T_HL_DEC -struct ip6t_HL_info { +struct ip6t_hl_info { __u8 mode; __u8 hop_limit; }; diff -uarN a/include/uapi/linux/usb/video.h b/include/uapi/linux/usb/video.h --- a/include/uapi/linux/usb/video.h 2016-08-28 13:19:20.000000000 +0300 +++ b/include/uapi/linux/usb/video.h 2019-02-14 05:41:45.000000000 +0300 @@ -53,6 +53,9 @@ #define UVC_VS_FORMAT_FRAME_BASED 0x10 #define UVC_VS_FRAME_FRAME_BASED 0x11 #define UVC_VS_FORMAT_STREAM_BASED 0x12 +#define UVC_VS_FORMAT_H264 0x13 +#define UVC_VS_FRAME_H264 0x14 + /* A.7. Video Class-Specific Endpoint Descriptor Subtypes */ #define UVC_EP_UNDEFINED 0x00 @@ -290,19 +293,22 @@ } __attribute__ ((packed)) /* 3.7.2.5. Processing Unit Descriptor */ -struct uvc_processing_unit_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bUnitID; - __u8 bSourceID; - __u16 wMaxMultiplier; - __u8 bControlSize; - __u8 bmControls[2]; - __u8 iProcessing; -} __attribute__((__packed__)); +#define UVC_PROCESSING_UNIT_DESCRIPTOR(n) \ + uvc_processing_unit_descriptor_##n -#define UVC_DT_PROCESSING_UNIT_SIZE(n) (9+(n)) +#define DECLARE_UVC_PROCESSING_UNIT_DESCRIPTOR(n) \ +struct UVC_PROCESSING_UNIT_DESCRIPTOR(n) { \ + __u8 bLength; \ + __u8 bDescriptorType; \ + __u8 bDescriptorSubType; \ + __u8 bUnitID; \ + __u8 bSourceID; \ + __u16 wMaxMultiplier; \ + __u8 bControlSize; \ + __u8 bmControls[n]; \ + __u8 iProcessing; \ + __u8 bmVideoStandards; \ +} __attribute__((__packed__)) /* 3.7.2.6. Extension Unit Descriptor */ struct uvc_extension_unit_descriptor { @@ -564,5 +570,44 @@ __u32 dwFrameInterval[n]; \ } __attribute__ ((packed)) +struct uvc_format_h264_base { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + __u8 bFormatIndex; + __u8 bNumFrameDescriptors; + __u8 guidFormat[16]; + __u8 bBitsPerPixel; + __u8 bDefaultFrameIndex; + __u8 bAspectRatioX; + __u8 bAspectRatioY; + __u8 bmInterfaceFlags; + __u8 bCopyProtect; + __u8 bVariableSize; +} __attribute__((__packed__)); + +#define UVC_DT_FRAME_H264_SIZE(n) (26+4*(n)) + +#define UVC_FRAME_H264_BASE(n) \ + uvc_frame_h264_base##n + +#define DECLARE_UVC_FRAME_H264_BASE(n) \ +struct UVC_FRAME_H264_BASE(n) { \ + __u8 bLength; \ + __u8 bDescriptorType; \ + __u8 bDescriptorSubType; \ + __u8 bFrameIndex; \ + __u8 bmCapabilities; \ + __u16 wWidth; \ + __u16 wHeight; \ + __u32 dwMinBitRate; \ + __u32 dwMaxBitRate; \ + __u32 dwDefaultFrameInterval; \ + __u8 bFrameIntervalType; \ + __u32 dwBytesPerLine; \ + __u32 dwFrameInterval[n]; \ +} __attribute__ ((packed)) + + #endif /* __LINUX_USB_VIDEO_H */ diff -uarN a/init/main.c b/init/main.c --- a/init/main.c 2016-08-28 13:19:20.000000000 +0300 +++ b/init/main.c 2018-11-21 06:44:38.000000000 +0300 @@ -469,6 +469,47 @@ vmalloc_init(); } +extern struct tag_xminfo xminfo; +static int xminfo_show(struct seq_file *file, void *iter) +{ + seq_printf(file, "entry: vpn ppn asid size valid wired\n"); + seq_printf(file, "######XMINFO######\n"); + seq_printf(file, "DATE:%s\n", __DATE__); + seq_printf(file, "HWID:%s\n", xminfo.hwid); + seq_printf(file, "ethaddr:%s\n", xminfo.ethaddr); + seq_printf(file, "xmauto:%d\n", xminfo.xmauto); + seq_printf(file, "xmuart:%d\n", xminfo.xmuart); + seq_printf(file, "ID:%s\n", xminfo.p_id); + seq_printf(file, "##################\n"); + return 0; +} +static int xminfo_open(struct inode *inode, struct file *file) +{ + return single_open(file, xminfo_show, inode->i_private); +} + +static const struct file_operations xminfo_fops = { + .owner = THIS_MODULE, + .open = xminfo_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + + +static int __init proc_xminfo_create(void) +{ + struct proc_dir_entry *p; + proc_mkdir("xm", NULL); + p = proc_create_data("xm/xminfo", 0400, NULL, &xminfo_fops, NULL); + if (NULL == p){ + printk("create xminfo proc failed\n"); + return -1; + } + return 0; +} + + asmlinkage void __init start_kernel(void) { char * command_line; @@ -624,6 +665,7 @@ page_writeback_init(); #ifdef CONFIG_PROC_FS proc_root_init(); + proc_xminfo_create(); #endif cgroup_init(); cpuset_init(); @@ -844,6 +886,7 @@ pr_err("Failed to execute %s. Attempting defaults...\n", execute_command); } + if (!run_init_process("/sbin/init") || !run_init_process("/etc/init") || !run_init_process("/bin/init") || diff -uarN a/kernel/printk.c b/kernel/printk.c --- a/kernel/printk.c 2016-08-28 13:19:20.000000000 +0300 +++ b/kernel/printk.c 2018-11-21 06:44:38.000000000 +0300 @@ -45,6 +45,7 @@ #include #include #include +#include #include @@ -1784,12 +1785,23 @@ /* * Set up a list of consoles. Called from init/main.c */ +extern struct tag_xminfo xminfo; static int __init console_setup(char *str) { char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for index */ char *s, *options, *brl_options = NULL; int idx; + if (xminfo.xmuart == 1) + { + strcpy(buf, "null"); + idx = 0; + options = NULL; + __add_preferred_console(buf, idx, options, brl_options); + console_set_on_cmdline = 1; + return 1; + } + #ifdef CONFIG_A11Y_BRAILLE_CONSOLE if (!memcmp(str, "brl,", 4)) { brl_options = ""; diff -uarN a/net/netfilter/xt_DSCP.c b/net/netfilter/xt_DSCP.c --- a/net/netfilter/xt_DSCP.c 2016-08-28 13:19:20.000000000 +0300 +++ b/net/netfilter/xt_DSCP.c 2018-11-21 06:44:38.000000000 +0300 @@ -1,14 +1,11 @@ -/* x_tables module for setting the IPv4/IPv6 DSCP field, Version 1.8 +/* IP tables module for matching the value of the IPv4/IPv6 DSCP field * * (C) 2002 by Harald Welte - * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. - * - * See RFC2474 for a description of the DSCP field within the IP Header. -*/ + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include @@ -17,148 +14,102 @@ #include #include -#include +#include MODULE_AUTHOR("Harald Welte "); -MODULE_DESCRIPTION("Xtables: DSCP/TOS field modification"); +MODULE_DESCRIPTION("Xtables: DSCP/TOS field match"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("ipt_DSCP"); -MODULE_ALIAS("ip6t_DSCP"); -MODULE_ALIAS("ipt_TOS"); -MODULE_ALIAS("ip6t_TOS"); +MODULE_ALIAS("ipt_dscp"); +MODULE_ALIAS("ip6t_dscp"); +MODULE_ALIAS("ipt_tos"); +MODULE_ALIAS("ip6t_tos"); -static unsigned int -dscp_tg(struct sk_buff *skb, const struct xt_action_param *par) +static bool +dscp_mt(const struct sk_buff *skb, struct xt_action_param *par) { - const struct xt_DSCP_info *dinfo = par->targinfo; + const struct xt_dscp_info *info = par->matchinfo; u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT; - if (dscp != dinfo->dscp) { - if (!skb_make_writable(skb, sizeof(struct iphdr))) - return NF_DROP; - - ipv4_change_dsfield(ip_hdr(skb), (__u8)(~XT_DSCP_MASK), - dinfo->dscp << XT_DSCP_SHIFT); - - } - return XT_CONTINUE; + return (dscp == info->dscp) ^ !!info->invert; } -static unsigned int -dscp_tg6(struct sk_buff *skb, const struct xt_action_param *par) +static bool +dscp_mt6(const struct sk_buff *skb, struct xt_action_param *par) { - const struct xt_DSCP_info *dinfo = par->targinfo; + const struct xt_dscp_info *info = par->matchinfo; u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT; - if (dscp != dinfo->dscp) { - if (!skb_make_writable(skb, sizeof(struct ipv6hdr))) - return NF_DROP; - - ipv6_change_dsfield(ipv6_hdr(skb), (__u8)(~XT_DSCP_MASK), - dinfo->dscp << XT_DSCP_SHIFT); - } - return XT_CONTINUE; + return (dscp == info->dscp) ^ !!info->invert; } -static int dscp_tg_check(const struct xt_tgchk_param *par) +static int dscp_mt_check(const struct xt_mtchk_param *par) { - const struct xt_DSCP_info *info = par->targinfo; + const struct xt_dscp_info *info = par->matchinfo; if (info->dscp > XT_DSCP_MAX) { pr_info("dscp %x out of range\n", info->dscp); return -EDOM; } - return 0; -} -static unsigned int -tos_tg(struct sk_buff *skb, const struct xt_action_param *par) -{ - const struct xt_tos_target_info *info = par->targinfo; - struct iphdr *iph = ip_hdr(skb); - u_int8_t orig, nv; - - orig = ipv4_get_dsfield(iph); - nv = (orig & ~info->tos_mask) ^ info->tos_value; - - if (orig != nv) { - if (!skb_make_writable(skb, sizeof(struct iphdr))) - return NF_DROP; - iph = ip_hdr(skb); - ipv4_change_dsfield(iph, 0, nv); - } - - return XT_CONTINUE; + return 0; } -static unsigned int -tos_tg6(struct sk_buff *skb, const struct xt_action_param *par) +static bool tos_mt(const struct sk_buff *skb, struct xt_action_param *par) { - const struct xt_tos_target_info *info = par->targinfo; - struct ipv6hdr *iph = ipv6_hdr(skb); - u_int8_t orig, nv; - - orig = ipv6_get_dsfield(iph); - nv = (orig & ~info->tos_mask) ^ info->tos_value; - - if (orig != nv) { - if (!skb_make_writable(skb, sizeof(struct iphdr))) - return NF_DROP; - iph = ipv6_hdr(skb); - ipv6_change_dsfield(iph, 0, nv); - } + const struct xt_tos_match_info *info = par->matchinfo; - return XT_CONTINUE; + if (par->family == NFPROTO_IPV4) + return ((ip_hdr(skb)->tos & info->tos_mask) == + info->tos_value) ^ !!info->invert; + else + return ((ipv6_get_dsfield(ipv6_hdr(skb)) & info->tos_mask) == + info->tos_value) ^ !!info->invert; } -static struct xt_target dscp_tg_reg[] __read_mostly = { +static struct xt_match dscp_mt_reg[] __read_mostly = { { - .name = "DSCP", + .name = "dscp", .family = NFPROTO_IPV4, - .checkentry = dscp_tg_check, - .target = dscp_tg, - .targetsize = sizeof(struct xt_DSCP_info), - .table = "mangle", + .checkentry = dscp_mt_check, + .match = dscp_mt, + .matchsize = sizeof(struct xt_dscp_info), .me = THIS_MODULE, }, { - .name = "DSCP", + .name = "dscp", .family = NFPROTO_IPV6, - .checkentry = dscp_tg_check, - .target = dscp_tg6, - .targetsize = sizeof(struct xt_DSCP_info), - .table = "mangle", + .checkentry = dscp_mt_check, + .match = dscp_mt6, + .matchsize = sizeof(struct xt_dscp_info), .me = THIS_MODULE, }, { - .name = "TOS", + .name = "tos", .revision = 1, .family = NFPROTO_IPV4, - .table = "mangle", - .target = tos_tg, - .targetsize = sizeof(struct xt_tos_target_info), + .match = tos_mt, + .matchsize = sizeof(struct xt_tos_match_info), .me = THIS_MODULE, }, { - .name = "TOS", + .name = "tos", .revision = 1, .family = NFPROTO_IPV6, - .table = "mangle", - .target = tos_tg6, - .targetsize = sizeof(struct xt_tos_target_info), + .match = tos_mt, + .matchsize = sizeof(struct xt_tos_match_info), .me = THIS_MODULE, }, }; -static int __init dscp_tg_init(void) +static int __init dscp_mt_init(void) { - return xt_register_targets(dscp_tg_reg, ARRAY_SIZE(dscp_tg_reg)); + return xt_register_matches(dscp_mt_reg, ARRAY_SIZE(dscp_mt_reg)); } -static void __exit dscp_tg_exit(void) +static void __exit dscp_mt_exit(void) { - xt_unregister_targets(dscp_tg_reg, ARRAY_SIZE(dscp_tg_reg)); + xt_unregister_matches(dscp_mt_reg, ARRAY_SIZE(dscp_mt_reg)); } -module_init(dscp_tg_init); -module_exit(dscp_tg_exit); +module_init(dscp_mt_init); +module_exit(dscp_mt_exit); diff -uarN a/net/netfilter/xt_HL.c b/net/netfilter/xt_HL.c --- a/net/netfilter/xt_HL.c 2016-08-28 13:19:20.000000000 +0300 +++ b/net/netfilter/xt_HL.c 2018-11-21 06:44:38.000000000 +0300 @@ -1,169 +1,96 @@ /* - * TTL modification target for IP tables - * (C) 2000,2005 by Harald Welte + * IP tables module for matching the value of the TTL + * (C) 2000,2001 by Harald Welte * - * Hop Limit modification target for ip6tables - * Maciej Soltysiak + * Hop Limit matching module + * (C) 2001-2002 Maciej Soltysiak * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include -#include + #include #include -#include +#include +#include #include -#include -#include +#include +#include -MODULE_AUTHOR("Harald Welte "); MODULE_AUTHOR("Maciej Soltysiak "); -MODULE_DESCRIPTION("Xtables: Hoplimit/TTL Limit field modification target"); +MODULE_DESCRIPTION("Xtables: Hoplimit/TTL field match"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("ipt_ttl"); +MODULE_ALIAS("ip6t_hl"); -static unsigned int -ttl_tg(struct sk_buff *skb, const struct xt_action_param *par) +static bool ttl_mt(const struct sk_buff *skb, struct xt_action_param *par) { - struct iphdr *iph; - const struct ipt_TTL_info *info = par->targinfo; - int new_ttl; - - if (!skb_make_writable(skb, skb->len)) - return NF_DROP; - - iph = ip_hdr(skb); + const struct ipt_ttl_info *info = par->matchinfo; + const u8 ttl = ip_hdr(skb)->ttl; switch (info->mode) { - case IPT_TTL_SET: - new_ttl = info->ttl; - break; - case IPT_TTL_INC: - new_ttl = iph->ttl + info->ttl; - if (new_ttl > 255) - new_ttl = 255; - break; - case IPT_TTL_DEC: - new_ttl = iph->ttl - info->ttl; - if (new_ttl < 0) - new_ttl = 0; - break; - default: - new_ttl = iph->ttl; - break; - } - - if (new_ttl != iph->ttl) { - csum_replace2(&iph->check, htons(iph->ttl << 8), - htons(new_ttl << 8)); - iph->ttl = new_ttl; + case IPT_TTL_EQ: + return ttl == info->ttl; + case IPT_TTL_NE: + return ttl != info->ttl; + case IPT_TTL_LT: + return ttl < info->ttl; + case IPT_TTL_GT: + return ttl > info->ttl; } - return XT_CONTINUE; + return false; } -static unsigned int -hl_tg6(struct sk_buff *skb, const struct xt_action_param *par) +static bool hl_mt6(const struct sk_buff *skb, struct xt_action_param *par) { - struct ipv6hdr *ip6h; - const struct ip6t_HL_info *info = par->targinfo; - int new_hl; - - if (!skb_make_writable(skb, skb->len)) - return NF_DROP; - - ip6h = ipv6_hdr(skb); + const struct ip6t_hl_info *info = par->matchinfo; + const struct ipv6hdr *ip6h = ipv6_hdr(skb); switch (info->mode) { - case IP6T_HL_SET: - new_hl = info->hop_limit; - break; - case IP6T_HL_INC: - new_hl = ip6h->hop_limit + info->hop_limit; - if (new_hl > 255) - new_hl = 255; - break; - case IP6T_HL_DEC: - new_hl = ip6h->hop_limit - info->hop_limit; - if (new_hl < 0) - new_hl = 0; - break; - default: - new_hl = ip6h->hop_limit; - break; + case IP6T_HL_EQ: + return ip6h->hop_limit == info->hop_limit; + case IP6T_HL_NE: + return ip6h->hop_limit != info->hop_limit; + case IP6T_HL_LT: + return ip6h->hop_limit < info->hop_limit; + case IP6T_HL_GT: + return ip6h->hop_limit > info->hop_limit; } - ip6h->hop_limit = new_hl; - - return XT_CONTINUE; -} - -static int ttl_tg_check(const struct xt_tgchk_param *par) -{ - const struct ipt_TTL_info *info = par->targinfo; - - if (info->mode > IPT_TTL_MAXMODE) { - pr_info("TTL: invalid or unknown mode %u\n", info->mode); - return -EINVAL; - } - if (info->mode != IPT_TTL_SET && info->ttl == 0) - return -EINVAL; - return 0; -} - -static int hl_tg6_check(const struct xt_tgchk_param *par) -{ - const struct ip6t_HL_info *info = par->targinfo; - - if (info->mode > IP6T_HL_MAXMODE) { - pr_info("invalid or unknown mode %u\n", info->mode); - return -EINVAL; - } - if (info->mode != IP6T_HL_SET && info->hop_limit == 0) { - pr_info("increment/decrement does not " - "make sense with value 0\n"); - return -EINVAL; - } - return 0; + return false; } -static struct xt_target hl_tg_reg[] __read_mostly = { +static struct xt_match hl_mt_reg[] __read_mostly = { { - .name = "TTL", + .name = "ttl", .revision = 0, .family = NFPROTO_IPV4, - .target = ttl_tg, - .targetsize = sizeof(struct ipt_TTL_info), - .table = "mangle", - .checkentry = ttl_tg_check, + .match = ttl_mt, + .matchsize = sizeof(struct ipt_ttl_info), .me = THIS_MODULE, }, { - .name = "HL", + .name = "hl", .revision = 0, .family = NFPROTO_IPV6, - .target = hl_tg6, - .targetsize = sizeof(struct ip6t_HL_info), - .table = "mangle", - .checkentry = hl_tg6_check, + .match = hl_mt6, + .matchsize = sizeof(struct ip6t_hl_info), .me = THIS_MODULE, }, }; -static int __init hl_tg_init(void) +static int __init hl_mt_init(void) { - return xt_register_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg)); + return xt_register_matches(hl_mt_reg, ARRAY_SIZE(hl_mt_reg)); } -static void __exit hl_tg_exit(void) +static void __exit hl_mt_exit(void) { - xt_unregister_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg)); + xt_unregister_matches(hl_mt_reg, ARRAY_SIZE(hl_mt_reg)); } -module_init(hl_tg_init); -module_exit(hl_tg_exit); -MODULE_ALIAS("ipt_TTL"); -MODULE_ALIAS("ip6t_HL"); +module_init(hl_mt_init); +module_exit(hl_mt_exit); diff -uarN a/net/netfilter/xt_RATEEST.c b/net/netfilter/xt_RATEEST.c --- a/net/netfilter/xt_RATEEST.c 2016-08-28 13:19:20.000000000 +0300 +++ b/net/netfilter/xt_RATEEST.c 2018-11-21 06:44:38.000000000 +0300 @@ -8,187 +8,150 @@ #include #include #include -#include -#include -#include -#include -#include -#include #include -#include +#include #include -static DEFINE_MUTEX(xt_rateest_mutex); -#define RATEEST_HSIZE 16 -static struct hlist_head rateest_hash[RATEEST_HSIZE] __read_mostly; -static unsigned int jhash_rnd __read_mostly; -static bool rnd_inited __read_mostly; - -static unsigned int xt_rateest_hash(const char *name) -{ - return jhash(name, FIELD_SIZEOF(struct xt_rateest, name), jhash_rnd) & - (RATEEST_HSIZE - 1); -} - -static void xt_rateest_hash_insert(struct xt_rateest *est) +static bool +xt_rateest_mt(const struct sk_buff *skb, struct xt_action_param *par) { - unsigned int h; - - h = xt_rateest_hash(est->name); - hlist_add_head(&est->list, &rateest_hash[h]); -} - -struct xt_rateest *xt_rateest_lookup(const char *name) -{ - struct xt_rateest *est; - unsigned int h; + const struct xt_rateest_match_info *info = par->matchinfo; + struct gnet_stats_rate_est *r; + u_int32_t bps1, bps2, pps1, pps2; + bool ret = true; + + spin_lock_bh(&info->est1->lock); + r = &info->est1->rstats; + if (info->flags & XT_RATEEST_MATCH_DELTA) { + bps1 = info->bps1 >= r->bps ? info->bps1 - r->bps : 0; + pps1 = info->pps1 >= r->pps ? info->pps1 - r->pps : 0; + } else { + bps1 = r->bps; + pps1 = r->pps; + } + spin_unlock_bh(&info->est1->lock); - h = xt_rateest_hash(name); - mutex_lock(&xt_rateest_mutex); - hlist_for_each_entry(est, &rateest_hash[h], list) { - if (strcmp(est->name, name) == 0) { - est->refcnt++; - mutex_unlock(&xt_rateest_mutex); - return est; + if (info->flags & XT_RATEEST_MATCH_ABS) { + bps2 = info->bps2; + pps2 = info->pps2; + } else { + spin_lock_bh(&info->est2->lock); + r = &info->est2->rstats; + if (info->flags & XT_RATEEST_MATCH_DELTA) { + bps2 = info->bps2 >= r->bps ? info->bps2 - r->bps : 0; + pps2 = info->pps2 >= r->pps ? info->pps2 - r->pps : 0; + } else { + bps2 = r->bps; + pps2 = r->pps; } + spin_unlock_bh(&info->est2->lock); } - mutex_unlock(&xt_rateest_mutex); - return NULL; -} -EXPORT_SYMBOL_GPL(xt_rateest_lookup); -void xt_rateest_put(struct xt_rateest *est) -{ - mutex_lock(&xt_rateest_mutex); - if (--est->refcnt == 0) { - hlist_del(&est->list); - gen_kill_estimator(&est->bstats, &est->rstats); - /* - * gen_estimator est_timer() might access est->lock or bstats, - * wait a RCU grace period before freeing 'est' - */ - kfree_rcu(est, rcu); + switch (info->mode) { + case XT_RATEEST_MATCH_LT: + if (info->flags & XT_RATEEST_MATCH_BPS) + ret &= bps1 < bps2; + if (info->flags & XT_RATEEST_MATCH_PPS) + ret &= pps1 < pps2; + break; + case XT_RATEEST_MATCH_GT: + if (info->flags & XT_RATEEST_MATCH_BPS) + ret &= bps1 > bps2; + if (info->flags & XT_RATEEST_MATCH_PPS) + ret &= pps1 > pps2; + break; + case XT_RATEEST_MATCH_EQ: + if (info->flags & XT_RATEEST_MATCH_BPS) + ret &= bps1 == bps2; + if (info->flags & XT_RATEEST_MATCH_PPS) + ret &= pps1 == pps2; + break; } - mutex_unlock(&xt_rateest_mutex); + + ret ^= info->flags & XT_RATEEST_MATCH_INVERT ? true : false; + return ret; } -EXPORT_SYMBOL_GPL(xt_rateest_put); -static unsigned int -xt_rateest_tg(struct sk_buff *skb, const struct xt_action_param *par) +static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par) { - const struct xt_rateest_target_info *info = par->targinfo; - struct gnet_stats_basic_packed *stats = &info->est->bstats; + struct xt_rateest_match_info *info = par->matchinfo; + struct xt_rateest *est1, *est2; + int ret = -EINVAL; - spin_lock_bh(&info->est->lock); - stats->bytes += skb->len; - stats->packets++; - spin_unlock_bh(&info->est->lock); - - return XT_CONTINUE; -} + if (hweight32(info->flags & (XT_RATEEST_MATCH_ABS | + XT_RATEEST_MATCH_REL)) != 1) + goto err1; -static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par) -{ - struct xt_rateest_target_info *info = par->targinfo; - struct xt_rateest *est; - struct { - struct nlattr opt; - struct gnet_estimator est; - } cfg; - int ret; - - if (unlikely(!rnd_inited)) { - get_random_bytes(&jhash_rnd, sizeof(jhash_rnd)); - rnd_inited = true; - } + if (!(info->flags & (XT_RATEEST_MATCH_BPS | XT_RATEEST_MATCH_PPS))) + goto err1; - est = xt_rateest_lookup(info->name); - if (est) { - /* - * If estimator parameters are specified, they must match the - * existing estimator. - */ - if ((!info->interval && !info->ewma_log) || - (info->interval != est->params.interval || - info->ewma_log != est->params.ewma_log)) { - xt_rateest_put(est); - return -EINVAL; - } - info->est = est; - return 0; + switch (info->mode) { + case XT_RATEEST_MATCH_EQ: + case XT_RATEEST_MATCH_LT: + case XT_RATEEST_MATCH_GT: + break; + default: + goto err1; } - ret = -ENOMEM; - est = kzalloc(sizeof(*est), GFP_KERNEL); - if (!est) + ret = -ENOENT; + est1 = xt_rateest_lookup(info->name1); + if (!est1) goto err1; - strlcpy(est->name, info->name, sizeof(est->name)); - spin_lock_init(&est->lock); - est->refcnt = 1; - est->params.interval = info->interval; - est->params.ewma_log = info->ewma_log; - - cfg.opt.nla_len = nla_attr_size(sizeof(cfg.est)); - cfg.opt.nla_type = TCA_STATS_RATE_EST; - cfg.est.interval = info->interval; - cfg.est.ewma_log = info->ewma_log; - - ret = gen_new_estimator(&est->bstats, &est->rstats, - &est->lock, &cfg.opt); - if (ret < 0) - goto err2; + est2 = NULL; + if (info->flags & XT_RATEEST_MATCH_REL) { + est2 = xt_rateest_lookup(info->name2); + if (!est2) + goto err2; + } - info->est = est; - xt_rateest_hash_insert(est); + info->est1 = est1; + info->est2 = est2; return 0; err2: - kfree(est); + xt_rateest_put(est1); err1: return ret; } -static void xt_rateest_tg_destroy(const struct xt_tgdtor_param *par) +static void xt_rateest_mt_destroy(const struct xt_mtdtor_param *par) { - struct xt_rateest_target_info *info = par->targinfo; + struct xt_rateest_match_info *info = par->matchinfo; - xt_rateest_put(info->est); + xt_rateest_put(info->est1); + if (info->est2) + xt_rateest_put(info->est2); } -static struct xt_target xt_rateest_tg_reg __read_mostly = { - .name = "RATEEST", +static struct xt_match xt_rateest_mt_reg __read_mostly = { + .name = "rateest", .revision = 0, .family = NFPROTO_UNSPEC, - .target = xt_rateest_tg, - .checkentry = xt_rateest_tg_checkentry, - .destroy = xt_rateest_tg_destroy, - .targetsize = sizeof(struct xt_rateest_target_info), + .match = xt_rateest_mt, + .checkentry = xt_rateest_mt_checkentry, + .destroy = xt_rateest_mt_destroy, + .matchsize = sizeof(struct xt_rateest_match_info), .me = THIS_MODULE, }; -static int __init xt_rateest_tg_init(void) +static int __init xt_rateest_mt_init(void) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(rateest_hash); i++) - INIT_HLIST_HEAD(&rateest_hash[i]); - - return xt_register_target(&xt_rateest_tg_reg); + return xt_register_match(&xt_rateest_mt_reg); } -static void __exit xt_rateest_tg_fini(void) +static void __exit xt_rateest_mt_fini(void) { - xt_unregister_target(&xt_rateest_tg_reg); + xt_unregister_match(&xt_rateest_mt_reg); } - MODULE_AUTHOR("Patrick McHardy "); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Xtables: packet rate estimator"); -MODULE_ALIAS("ipt_RATEEST"); -MODULE_ALIAS("ip6t_RATEEST"); -module_init(xt_rateest_tg_init); -module_exit(xt_rateest_tg_fini); +MODULE_DESCRIPTION("xtables rate estimator match"); +MODULE_ALIAS("ipt_rateest"); +MODULE_ALIAS("ip6t_rateest"); +module_init(xt_rateest_mt_init); +module_exit(xt_rateest_mt_fini); diff -uarN a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c --- a/net/netfilter/xt_TCPMSS.c 2016-08-28 13:19:20.000000000 +0300 +++ b/net/netfilter/xt_TCPMSS.c 2018-11-21 06:44:38.000000000 +0300 @@ -1,336 +1,110 @@ -/* - * This is a module which is used for setting the MSS option in TCP packets. - * - * Copyright (C) 2000 Marc Boucher - * Copyright (C) 2007 Patrick McHardy +/* Kernel module to match TCP MSS values. */ + +/* Copyright (C) 2000 Marc Boucher + * Portions (C) 2005 by Harald Welte * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include + #include #include -#include -#include -#include MODULE_LICENSE("GPL"); MODULE_AUTHOR("Marc Boucher "); -MODULE_DESCRIPTION("Xtables: TCP Maximum Segment Size (MSS) adjustment"); -MODULE_ALIAS("ipt_TCPMSS"); -MODULE_ALIAS("ip6t_TCPMSS"); +MODULE_DESCRIPTION("Xtables: TCP MSS match"); +MODULE_ALIAS("ipt_tcpmss"); +MODULE_ALIAS("ip6t_tcpmss"); + +static bool +tcpmss_mt(const struct sk_buff *skb, struct xt_action_param *par) +{ + const struct xt_tcpmss_match_info *info = par->matchinfo; + const struct tcphdr *th; + struct tcphdr _tcph; + /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */ + const u_int8_t *op; + u8 _opt[15 * 4 - sizeof(_tcph)]; + unsigned int i, optlen; + + /* If we don't have the whole header, drop packet. */ + th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph); + if (th == NULL) + goto dropit; + + /* Malformed. */ + if (th->doff*4 < sizeof(*th)) + goto dropit; + + optlen = th->doff*4 - sizeof(*th); + if (!optlen) + goto out; + + /* Truncated options. */ + op = skb_header_pointer(skb, par->thoff + sizeof(*th), optlen, _opt); + if (op == NULL) + goto dropit; + + for (i = 0; i < optlen; ) { + if (op[i] == TCPOPT_MSS + && (optlen - i) >= TCPOLEN_MSS + && op[i+1] == TCPOLEN_MSS) { + u_int16_t mssval; -static inline unsigned int -optlen(const u_int8_t *opt, unsigned int offset) -{ - /* Beware zero-length options: make finite progress */ - if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0) - return 1; - else - return opt[offset+1]; -} + mssval = (op[i+2] << 8) | op[i+3]; -static int -tcpmss_mangle_packet(struct sk_buff *skb, - const struct xt_action_param *par, - unsigned int in_mtu, - unsigned int tcphoff, - unsigned int minlen) -{ - const struct xt_tcpmss_info *info = par->targinfo; - struct tcphdr *tcph; - unsigned int tcplen, i; - __be16 oldval; - u16 newmss; - u8 *opt; - - /* This is a fragment, no TCP header is available */ - if (par->fragoff != 0) - return XT_CONTINUE; - - if (!skb_make_writable(skb, skb->len)) - return -1; - - tcplen = skb->len - tcphoff; - tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); - - /* Header cannot be larger than the packet */ - if (tcplen < tcph->doff*4) - return -1; - - if (info->mss == XT_TCPMSS_CLAMP_PMTU) { - if (dst_mtu(skb_dst(skb)) <= minlen) { - net_err_ratelimited("unknown or invalid path-MTU (%u)\n", - dst_mtu(skb_dst(skb))); - return -1; - } - if (in_mtu <= minlen) { - net_err_ratelimited("unknown or invalid path-MTU (%u)\n", - in_mtu); - return -1; - } - newmss = min(dst_mtu(skb_dst(skb)), in_mtu) - minlen; - } else - newmss = info->mss; - - opt = (u_int8_t *)tcph; - for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) { - if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS && - opt[i+1] == TCPOLEN_MSS) { - u_int16_t oldmss; - - oldmss = (opt[i+2] << 8) | opt[i+3]; - - /* Never increase MSS, even when setting it, as - * doing so results in problems for hosts that rely - * on MSS being set correctly. - */ - if (oldmss <= newmss) - return 0; - - opt[i+2] = (newmss & 0xff00) >> 8; - opt[i+3] = newmss & 0x00ff; - - inet_proto_csum_replace2(&tcph->check, skb, - htons(oldmss), htons(newmss), - 0); - return 0; + return (mssval >= info->mss_min && + mssval <= info->mss_max) ^ info->invert; } + if (op[i] < 2) + i++; + else + i += op[i+1] ? : 1; } +out: + return info->invert; - /* There is data after the header so the option can't be added - without moving it, and doing so may make the SYN packet - itself too large. Accept the packet unmodified instead. */ - if (tcplen > tcph->doff*4) - return 0; - - /* - * MSS Option not found ?! add it.. - */ - if (skb_tailroom(skb) < TCPOLEN_MSS) { - if (pskb_expand_head(skb, 0, - TCPOLEN_MSS - skb_tailroom(skb), - GFP_ATOMIC)) - return -1; - tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); - } - - skb_put(skb, TCPOLEN_MSS); - - /* - * IPv4: RFC 1122 states "If an MSS option is not received at - * connection setup, TCP MUST assume a default send MSS of 536". - * IPv6: RFC 2460 states IPv6 has a minimum MTU of 1280 and a minimum - * length IPv6 header of 60, ergo the default MSS value is 1220 - * Since no MSS was provided, we must use the default values - */ - if (par->family == NFPROTO_IPV4) - newmss = min(newmss, (u16)536); - else - newmss = min(newmss, (u16)1220); - - opt = (u_int8_t *)tcph + sizeof(struct tcphdr); - memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr)); - - inet_proto_csum_replace2(&tcph->check, skb, - htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1); - opt[0] = TCPOPT_MSS; - opt[1] = TCPOLEN_MSS; - opt[2] = (newmss & 0xff00) >> 8; - opt[3] = newmss & 0x00ff; - - inet_proto_csum_replace4(&tcph->check, skb, 0, *((__be32 *)opt), 0); - - oldval = ((__be16 *)tcph)[6]; - tcph->doff += TCPOLEN_MSS/4; - inet_proto_csum_replace2(&tcph->check, skb, - oldval, ((__be16 *)tcph)[6], 0); - return TCPOLEN_MSS; -} - -static u_int32_t tcpmss_reverse_mtu(const struct sk_buff *skb, - unsigned int family) -{ - struct flowi fl; - const struct nf_afinfo *ai; - struct rtable *rt = NULL; - u_int32_t mtu = ~0U; - - if (family == PF_INET) { - struct flowi4 *fl4 = &fl.u.ip4; - memset(fl4, 0, sizeof(*fl4)); - fl4->daddr = ip_hdr(skb)->saddr; - } else { - struct flowi6 *fl6 = &fl.u.ip6; - - memset(fl6, 0, sizeof(*fl6)); - fl6->daddr = ipv6_hdr(skb)->saddr; - } - rcu_read_lock(); - ai = nf_get_afinfo(family); - if (ai != NULL) - ai->route(&init_net, (struct dst_entry **)&rt, &fl, false); - rcu_read_unlock(); - - if (rt != NULL) { - mtu = dst_mtu(&rt->dst); - dst_release(&rt->dst); - } - return mtu; -} - -static unsigned int -tcpmss_tg4(struct sk_buff *skb, const struct xt_action_param *par) -{ - struct iphdr *iph = ip_hdr(skb); - __be16 newlen; - int ret; - - ret = tcpmss_mangle_packet(skb, par, - tcpmss_reverse_mtu(skb, PF_INET), - iph->ihl * 4, - sizeof(*iph) + sizeof(struct tcphdr)); - if (ret < 0) - return NF_DROP; - if (ret > 0) { - iph = ip_hdr(skb); - newlen = htons(ntohs(iph->tot_len) + ret); - csum_replace2(&iph->check, iph->tot_len, newlen); - iph->tot_len = newlen; - } - return XT_CONTINUE; -} - -#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) -static unsigned int -tcpmss_tg6(struct sk_buff *skb, const struct xt_action_param *par) -{ - struct ipv6hdr *ipv6h = ipv6_hdr(skb); - u8 nexthdr; - __be16 frag_off; - int tcphoff; - int ret; - - nexthdr = ipv6h->nexthdr; - tcphoff = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr, &frag_off); - if (tcphoff < 0) - return NF_DROP; - ret = tcpmss_mangle_packet(skb, par, - tcpmss_reverse_mtu(skb, PF_INET6), - tcphoff, - sizeof(*ipv6h) + sizeof(struct tcphdr)); - if (ret < 0) - return NF_DROP; - if (ret > 0) { - ipv6h = ipv6_hdr(skb); - ipv6h->payload_len = htons(ntohs(ipv6h->payload_len) + ret); - } - return XT_CONTINUE; -} -#endif - -/* Must specify -p tcp --syn */ -static inline bool find_syn_match(const struct xt_entry_match *m) -{ - const struct xt_tcp *tcpinfo = (const struct xt_tcp *)m->data; - - if (strcmp(m->u.kernel.match->name, "tcp") == 0 && - tcpinfo->flg_cmp & TCPHDR_SYN && - !(tcpinfo->invflags & XT_TCP_INV_FLAGS)) - return true; - +dropit: + par->hotdrop = true; return false; } -static int tcpmss_tg4_check(const struct xt_tgchk_param *par) -{ - const struct xt_tcpmss_info *info = par->targinfo; - const struct ipt_entry *e = par->entryinfo; - const struct xt_entry_match *ematch; - - if (info->mss == XT_TCPMSS_CLAMP_PMTU && - (par->hook_mask & ~((1 << NF_INET_FORWARD) | - (1 << NF_INET_LOCAL_OUT) | - (1 << NF_INET_POST_ROUTING))) != 0) { - pr_info("path-MTU clamping only supported in " - "FORWARD, OUTPUT and POSTROUTING hooks\n"); - return -EINVAL; - } - xt_ematch_foreach(ematch, e) - if (find_syn_match(ematch)) - return 0; - pr_info("Only works on TCP SYN packets\n"); - return -EINVAL; -} - -#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) -static int tcpmss_tg6_check(const struct xt_tgchk_param *par) -{ - const struct xt_tcpmss_info *info = par->targinfo; - const struct ip6t_entry *e = par->entryinfo; - const struct xt_entry_match *ematch; - - if (info->mss == XT_TCPMSS_CLAMP_PMTU && - (par->hook_mask & ~((1 << NF_INET_FORWARD) | - (1 << NF_INET_LOCAL_OUT) | - (1 << NF_INET_POST_ROUTING))) != 0) { - pr_info("path-MTU clamping only supported in " - "FORWARD, OUTPUT and POSTROUTING hooks\n"); - return -EINVAL; - } - xt_ematch_foreach(ematch, e) - if (find_syn_match(ematch)) - return 0; - pr_info("Only works on TCP SYN packets\n"); - return -EINVAL; -} -#endif - -static struct xt_target tcpmss_tg_reg[] __read_mostly = { +static struct xt_match tcpmss_mt_reg[] __read_mostly = { { + .name = "tcpmss", .family = NFPROTO_IPV4, - .name = "TCPMSS", - .checkentry = tcpmss_tg4_check, - .target = tcpmss_tg4, - .targetsize = sizeof(struct xt_tcpmss_info), + .match = tcpmss_mt, + .matchsize = sizeof(struct xt_tcpmss_match_info), .proto = IPPROTO_TCP, .me = THIS_MODULE, }, -#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) { + .name = "tcpmss", .family = NFPROTO_IPV6, - .name = "TCPMSS", - .checkentry = tcpmss_tg6_check, - .target = tcpmss_tg6, - .targetsize = sizeof(struct xt_tcpmss_info), + .match = tcpmss_mt, + .matchsize = sizeof(struct xt_tcpmss_match_info), .proto = IPPROTO_TCP, .me = THIS_MODULE, }, -#endif }; -static int __init tcpmss_tg_init(void) +static int __init tcpmss_mt_init(void) { - return xt_register_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg)); + return xt_register_matches(tcpmss_mt_reg, ARRAY_SIZE(tcpmss_mt_reg)); } -static void __exit tcpmss_tg_exit(void) +static void __exit tcpmss_mt_exit(void) { - xt_unregister_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg)); + xt_unregister_matches(tcpmss_mt_reg, ARRAY_SIZE(tcpmss_mt_reg)); } -module_init(tcpmss_tg_init); -module_exit(tcpmss_tg_exit); +module_init(tcpmss_mt_init); +module_exit(tcpmss_mt_exit); diff -uarN a/scripts/setlocalversion b/scripts/setlocalversion --- a/scripts/setlocalversion 2016-08-28 13:19:20.000000000 +0300 +++ b/scripts/setlocalversion 2018-11-21 06:44:38.000000000 +0300 @@ -43,7 +43,7 @@ fi # Check for git and a git repo. - if test -d .git && head=`git rev-parse --verify --short HEAD 2>/dev/null`; then + if head=`git rev-parse --verify --short HEAD 2>/dev/null`; then # If we are at a tagged commit (like "v2.6.30-rc6"), we ignore # it, because this version is defined in the top level Makefile.