From db59a43981edb5e82a9189e1b9cec627ab6b2e4a Mon Sep 17 00:00:00 2001 From: mwx533604 Date: Mon, 5 Feb 2018 22:03:09 +0800 Subject: [PATCH] Drivers/DMA: support DMA function for hikey970. Add DMA code in kernel to support hisi dma for hikey970. Signed-off-by: mwx533604 --- arch/arm64/configs/hikey970_defconfig | 725 +++++++++++++++++ drivers/dma/Kconfig | 9 + drivers/dma/Makefile | 1 + drivers/dma/hisi_dma_64.c | 1053 +++++++++++++++++++++++++ 4 files changed, 1788 insertions(+) create mode 100755 arch/arm64/configs/hikey970_defconfig mode change 100644 => 100755 drivers/dma/Kconfig mode change 100644 => 100755 drivers/dma/Makefile create mode 100755 drivers/dma/hisi_dma_64.c diff --git a/arch/arm64/configs/hikey970_defconfig b/arch/arm64/configs/hikey970_defconfig new file mode 100755 index 000000000000..e7f60de4b254 --- /dev/null +++ b/arch/arm64/configs/hikey970_defconfig @@ -0,0 +1,725 @@ +CONFIG_POSIX_MQUEUE=y +# CONFIG_FHANDLE is not set +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_SCHED_WALT=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_SCHEDTUNE=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_BLK_CGROUP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_HUGETLB=y +CONFIG_CGROUP_PERF=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_AIO is not set +CONFIG_EMBEDDED=y +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_JUMP_LABEL=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_ARCH_SUNXI=y +CONFIG_ARCH_ALPINE=y +CONFIG_ARCH_BCM_IPROC=y +CONFIG_ARCH_BERLIN=y +CONFIG_ARCH_EXYNOS=y +CONFIG_ARCH_LAYERSCAPE=y +CONFIG_ARCH_LG1K=y +CONFIG_ARCH_HISI=y +CONFIG_ARCH_MEDIATEK=y +CONFIG_ARCH_MESON=y +CONFIG_ARCH_MVEBU=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_ROCKCHIP=y +CONFIG_ARCH_SEATTLE=y +CONFIG_ARCH_RENESAS=y +CONFIG_ARCH_R8A7795=y +CONFIG_ARCH_R8A7796=y +CONFIG_ARCH_STRATIX10=y +CONFIG_ARCH_TEGRA=y +CONFIG_ARCH_SPRD=y +CONFIG_ARCH_THUNDER=y +CONFIG_ARCH_UNIPHIER=y +CONFIG_ARCH_VEXPRESS=y +CONFIG_ARCH_VULCAN=y +CONFIG_ARCH_XGENE=y +CONFIG_ARCH_ZX=y +CONFIG_ARCH_ZYNQMP=y +CONFIG_PCI=y +CONFIG_PCI_IOV=y +CONFIG_PCI_AARDVARK=y +CONFIG_PCIE_RCAR=y +CONFIG_PCI_HOST_GENERIC=y +CONFIG_PCI_XGENE=y +CONFIG_PCI_LAYERSCAPE=y +CONFIG_PCI_HISI=y +CONFIG_PCIE_QCOM=y +CONFIG_PCIE_ARMADA_8K=y +CONFIG_PCIE_KIRIN=y +CONFIG_ARM64_VA_BITS_48=y +CONFIG_SCHED_MC=y +CONFIG_PREEMPT=y +CONFIG_KSM=y +CONFIG_TRANSPARENT_HUGEPAGE=y +CONFIG_CMA=y +CONFIG_SECCOMP=y +CONFIG_KEXEC=y +CONFIG_XEN=y +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +CONFIG_ARM64_SW_TTBR0_PAN=y +CONFIG_RANDOMIZE_BASE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_COMPAT=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_DEBUG=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_ARM_HISI_CPUIDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPUFREQ_DT=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_INET_ESP=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=m +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_IP6_NF_NAT=m +CONFIG_IP6_NF_TARGET_MASQUERADE=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_VLAN_8021Q_MVRP=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_CLS_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_CLS_ACT=y +CONFIG_BPF_JIT=y +CONFIG_BT=m +CONFIG_BT_LEDS=y +CONFIG_BT_HIDP=m +# CONFIG_BT_HS is not set +# CONFIG_BT_LE is not set +# CONFIG_BT_DEBUGFS is not set +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_LL=y +CONFIG_CFG80211=y +CONFIG_MAC80211=y +CONFIG_MAC80211_LEDS=y +CONFIG_RFKILL=y +CONFIG_RFKILL_REGULATOR=y +CONFIG_RFKILL_GPIO=y +CONFIG_NET_9P=y +CONFIG_NET_9P_VIRTIO=y +CONFIG_CAN=y +CONFIG_CAN_DEV=y +CONFIG_CAN_MCP251X=y +CONFIG_CAN_LEDS=y +CONFIG_CAN_DEBUG_DEVICES=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_DMA_CMA=y +CONFIG_CMA_SIZE_MBYTES=64 +CONFIG_MTD=y +CONFIG_MTD_M25P80=y +CONFIG_MTD_SPI_NOR=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_VIRTIO_BLK=y +CONFIG_SRAM=y +CONFIG_UID_SYS_STATS=y +CONFIG_HISI_HIKEY_USB=y +CONFIG_MEMORY_STATE_TIME=y +CONFIG_TI_ST=y +CONFIG_ST_HCI=y +# CONFIG_SCSI_PROC_FS is not set +CONFIG_BLK_DEV_SD=y +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_HISI_SAS=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_HISI=y +CONFIG_ATA=y +CONFIG_SATA_AHCI=y +CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_AHCI_CEVA=y +CONFIG_AHCI_MVEBU=y +CONFIG_AHCI_XGENE=y +CONFIG_AHCI_QORIQ=y +CONFIG_SATA_SIL24=y +CONFIG_SATA_RCAR=y +CONFIG_PATA_PLATFORM=y +CONFIG_PATA_OF_PLATFORM=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_TUN=y +CONFIG_VETH=m +CONFIG_VIRTIO_NET=y +CONFIG_AMD_XGBE=y +CONFIG_NET_XGENE=y +CONFIG_MACB=y +CONFIG_HNS_DSAF=y +CONFIG_HNS_ENET=y +CONFIG_E1000E=y +CONFIG_IGB=y +CONFIG_IGBVF=y +CONFIG_SKY2=y +CONFIG_R8168=y +CONFIG_RAVB=y +CONFIG_SMC91X=y +CONFIG_SMSC911X=y +CONFIG_STMMAC_ETH=m +CONFIG_MICREL_PHY=y +CONFIG_REALTEK_PHY=m +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_RTL8152=m +CONFIG_USB_USBNET=y +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_SR9800=m +CONFIG_USB_NET_SMSC75XX=m +CONFIG_USB_NET_SMSC95XX=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_MCS7830=m +CONFIG_WL18XX=y +CONFIG_WLCORE_SDIO=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYRESET=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PM8941_PWRKEY=y +CONFIG_INPUT_KEYCHORD=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +CONFIG_INPUT_HISI_POWERKEY=y +# CONFIG_SERIO_SERPORT is not set +CONFIG_SERIO_AMBAKMI=y +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_8250_MT6577=y +CONFIG_SERIAL_8250_UNIPHIER=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_SERIAL_MESON=y +CONFIG_SERIAL_MESON_CONSOLE=y +CONFIG_SERIAL_SAMSUNG=y +CONFIG_SERIAL_SAMSUNG_CONSOLE=y +CONFIG_SERIAL_TEGRA=y +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_NR_UARTS=11 +CONFIG_SERIAL_SH_SCI_CONSOLE=y +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_SERIAL_XILINX_PS_UART=y +CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y +CONFIG_SERIAL_MVEBU_UART=y +CONFIG_VIRTIO_CONSOLE=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y +CONFIG_I2C_MUX_PCA954x=y +CONFIG_I2C_DESIGNWARE_PLATFORM=y +CONFIG_I2C_IMX=y +CONFIG_I2C_MESON=y +CONFIG_I2C_MV64XXX=y +CONFIG_I2C_QUP=y +CONFIG_I2C_TEGRA=y +CONFIG_I2C_UNIPHIER_F=y +CONFIG_I2C_RCAR=y +CONFIG_I2C_CROS_EC_TUNNEL=y +CONFIG_SPI=y +CONFIG_SPI_MESON_SPIFC=m +CONFIG_SPI_ORION=y +CONFIG_SPI_PL022=y +CONFIG_SPI_QUP=y +CONFIG_SPI_S3C64XX=y +CONFIG_SPI_SPIDEV=m +CONFIG_SPMI=y +CONFIG_HISI_SPMI=y +CONFIG_HISI_PMIC_PMU_SPMI=y +CONFIG_HISI_REGULATOR_SPMI=y +CONFIG_PINCTRL_SINGLE=y +CONFIG_PINCTRL_MAX77620=y +CONFIG_PINCTRL_MSM8916=y +CONFIG_PINCTRL_MSM8996=y +CONFIG_PINCTRL_QDF2XXX=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_DWAPB=y +CONFIG_GPIO_PL061=y +CONFIG_GPIO_RCAR=y +CONFIG_GPIO_XGENE=y +CONFIG_GPIO_PCA953X=y +CONFIG_GPIO_PCA953X_IRQ=y +CONFIG_GPIO_MAX77620=y +CONFIG_POWER_RESET_HISI=y +CONFIG_POWER_RESET_MSM=y +CONFIG_POWER_RESET_XGENE=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_SYSCON_REBOOT_MODE=y +CONFIG_BATTERY_BQ27XXX=y +CONFIG_SENSORS_ARM_SCPI=y +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_INA2XX=m +CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR=y +CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_THERMAL_EMULATION=y +CONFIG_HISI_THERMAL=y +CONFIG_EXYNOS_THERMAL=y +CONFIG_WATCHDOG=y +CONFIG_S3C2410_WATCHDOG=y +CONFIG_MESON_GXBB_WATCHDOG=m +CONFIG_MESON_WATCHDOG=m +CONFIG_RENESAS_WDT=y +CONFIG_MFD_CROS_EC=y +CONFIG_MFD_CROS_EC_I2C=y +CONFIG_MFD_HI655X_PMIC=y +CONFIG_MFD_MAX77620=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_MFD_SEC_CORE=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_GPIO=y +CONFIG_REGULATOR_HI655X=y +CONFIG_REGULATOR_MAX77620=y +CONFIG_REGULATOR_PWM=y +CONFIG_REGULATOR_QCOM_SMD_RPM=y +CONFIG_REGULATOR_QCOM_SPMI=y +CONFIG_REGULATOR_S2MPS11=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VIDEO_HISI_ISP=y +CONFIG_DRM=y +CONFIG_DRM_NOUVEAU=m +CONFIG_DRM_TEGRA=m +CONFIG_DRM_PANEL_SIMPLE=m +CONFIG_DRM_I2C_ADV7511=m +CONFIG_DRM_I2C_ADV7533=m +CONFIG_DRM_HISI_KIRIN=m +CONFIG_DRM_KIRIN_960=y +CONFIG_HISI_FB_970=y +CONFIG_DRM_PANEL_HIKEY960_NTE300NTS=y +CONFIG_FB=y +CONFIG_FB_ARMCLCD=y +CONFIG_BACKLIGHT_GENERIC=m +CONFIG_BACKLIGHT_LP855X=m +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_SAMSUNG=y +CONFIG_SND_SOC_RCAR=y +CONFIG_SND_SOC_AK4613=y +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +CONFIG_HID_HOLTEK=y +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WALTOP=y +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_PRIMAX=y +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_WACOM=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_ZEROPLUS=y +CONFIG_HID_ZYDACRON=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_OTG=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_TEGRA=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_MSM=y +CONFIG_USB_EHCI_EXYNOS=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_EXYNOS=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_RENESAS_USBHS=m +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_HISI=y +CONFIG_USB_DWC2=y +CONFIG_USB_CHIPIDEA=y +CONFIG_USB_CHIPIDEA_UDC=y +CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_USB_ISP1760=y +CONFIG_TCPC_CLASS=y +CONFIG_USB_POWER_DELIVERY=y +CONFIG_TCPC_RT1711H=y +CONFIG_USB_HSIC_USB3503=y +CONFIG_USB_MSM_OTG=y +CONFIG_USB_ULPI=y +CONFIG_USB_GADGET=y +CONFIG_USB_RENESAS_USBHS_UDC=m +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_MMC=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_ARMMMCI=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_ACPI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_ESDHC=y +CONFIG_MMC_SDHCI_TEGRA=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SPI=y +CONFIG_MMC_SDHI=y +CONFIG_MMC_DW=y +CONFIG_MMC_DW_EXYNOS=y +CONFIG_MMC_DW_K3=y +CONFIG_MMC_SUNXI=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_SYSCON=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_CPU=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_MAX77686=y +CONFIG_RTC_DRV_S5M=y +CONFIG_RTC_DRV_DS3232=y +CONFIG_RTC_DRV_EFI=y +CONFIG_RTC_DRV_S3C=y +CONFIG_RTC_DRV_PL031=y +CONFIG_RTC_DRV_SUN6I=y +CONFIG_RTC_DRV_TEGRA=y +CONFIG_RTC_DRV_XGENE=y +CONFIG_DMADEVICES=y +CONFIG_HISI_DMA=y +CONFIG_PL330_DMA=y +CONFIG_TEGRA20_APB_DMA=y +CONFIG_QCOM_BAM_DMA=y +CONFIG_QCOM_HIDMA_MGMT=y +CONFIG_QCOM_HIDMA=y +CONFIG_RCAR_DMAC=y +CONFIG_VFIO=y +CONFIG_VFIO_PCI=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_MMIO=y +CONFIG_XEN_GNTDEV=y +CONFIG_XEN_GRANT_DEV_ALLOC=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ION=y +CONFIG_ION_HISI=y +CONFIG_COMMON_CLK_SCPI=y +CONFIG_COMMON_CLK_CS2000_CP=y +CONFIG_COMMON_CLK_S2MPS11=y +CONFIG_CLK_QORIQ=y +CONFIG_STUB_CLK_KIRIN970=y +CONFIG_COMMON_CLK_QCOM=y +CONFIG_MSM_GCC_8916=y +CONFIG_MSM_MMCC_8996=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_MAILBOX=y +CONFIG_ARM_MHU=y +CONFIG_HI6220_MBOX=y +CONFIG_PM_DEVFREQ=y +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y +CONFIG_DEVFREQ_GOV_USERSPACE=y +CONFIG_HISI_DDR_DEVFREQ=y +CONFIG_HISI_IOMMU_LPAE=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_SMEM=y +CONFIG_QCOM_SMD=y +CONFIG_QCOM_SMD_RPM=y +CONFIG_ARCH_TEGRA_132_SOC=y +CONFIG_ARCH_TEGRA_210_SOC=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_IIO=y +CONFIG_EXYNOS_ADC=y +CONFIG_PWM=y +CONFIG_PWM_SAMSUNG=y +CONFIG_PWM_TEGRA=m +CONFIG_PHY_RCAR_GEN3_USB2=y +CONFIG_PHY_HI6220_USB=y +CONFIG_PHY_KIRIN970_USB=y +CONFIG_PHY_XGENE=y +CONFIG_PHY_TEGRA_XUSB=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ARM_SCPI_PROTOCOL=y +CONFIG_ACPI=y +CONFIG_EXT2_FS=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS_POSIX_ACL=y +CONFIG_FANOTIFY=y +CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y +CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=y +CONFIG_CUSE=m +CONFIG_OVERLAY_FS=m +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_HUGETLBFS=y +CONFIG_EFIVAR_FS=y +CONFIG_SQUASHFS=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_RAM=y +CONFIG_9P_FS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_LOCKUP_DETECTOR=y +CONFIG_PANIC_TIMEOUT=5 +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_FTRACE is not set +CONFIG_MEMTEST=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_SECURITY_SELINUX=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_CRC32_ARM64=y +CONFIG_HI_VCODEC_VENC=y +CONFIG_HI_VCODEC_VDEC=y +CONFIG_MALI_PLATFORM_HIKEY970=y +CONFIG_MALI_MIDGARD=y +CONFIG_MALI_EXPERT=y +CONFIG_MALI_DEVFREQ=y +CONFIG_HISILICON_PLATFORM=y +CONFIG_HISILICON_PLATFORM_MAILBOX=y +CONFIG_HISI_MAILBOX=y +CONFIG_HISI_RPROC=y +CONFIG_HIFI_DSP_ONE_TRACK=y +CONFIG_HIFI_MAILBOX=y +CONFIG_HIFI_IPC=y +CONFIG_HIFI_IPC_3660=y +CONFIG_HIKEY970_HIFI=y +CONFIG_HISI_ASP_DMA=y +CONFIG_SND_I2S_HISI_I2S=y +CONFIG_HDMI_ADV7511_AUDIO=y diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig old mode 100644 new mode 100755 index 6f4ec1a589d1..9ad1d0e867ba --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -294,6 +294,15 @@ config HISI_ASP_DMA Support the DMA engine for Hisilicon Kirin platform devices. +config HISI_DMA + tristate "Hisilicon Kirin DMA support" + depends on ARCH_HISI + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + Support the DMA engine for Hisilicon Kirin platform + devices. + config LPC18XX_DMAMUX bool "NXP LPC18xx/43xx DMA MUX for PL080" depends on ARCH_LPC18XX || COMPILE_TEST diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile old mode 100644 new mode 100755 index f6b7636ba5d7..f4f7acf70126 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_TI_EDMA) += edma.o obj-$(CONFIG_XGENE_DMA) += xgene-dma.o obj-$(CONFIG_ZX_DMA) += zx296702_dma.o obj-$(CONFIG_HISI_ASP_DMA) += hisi_asp_dma.o +obj-$(CONFIG_HISI_DMA) += hisi_dma_64.o obj-y += qcom/ obj-y += xilinx/ diff --git a/drivers/dma/hisi_dma_64.c b/drivers/dma/hisi_dma_64.c new file mode 100755 index 000000000000..ce89a7a49c50 --- /dev/null +++ b/drivers/dma/hisi_dma_64.c @@ -0,0 +1,1053 @@ +/* + * Copyright (c) 2013 Linaro Ltd. + * Copyright (c) 2013 Hisilicon Limited. + * + * 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 +#include + +#include "virt-dma.h" +#define DMA_CHAN_MASK 0xffff +#define DRIVER_NAME "hisi-dma64" +#define DMA_ALIGN 3 +#define DMA_MAX_SIZE 0x1ffc + +#define INT_STAT 0x00 +#define INT_TC1 0x04 +#define INT_ERR1 0x0c +#define INT_ERR2 0x10 +#define INT_TC1_MASK 0x18 +#define INT_ERR1_MASK 0x20 +#define INT_ERR2_MASK 0x24 +#define INT_TC1_RAW 0x600 +#define INT_TC2_RAW 0x608 +#define INT_ERR1_RAW 0x610 +#define INT_ERR2_RAW 0x618 +#define CH_PRI 0x688 +#define CH_STAT 0x690 +#define DMA_CTRL 0x698 +#define CX_CUR_CNT 0x404 +#define CX_LLI_H 0x804 +#define CX_LLI_L 0x800 +#define CX_CNT 0x81C +#define CX_SRC_L 0x820 +#define CX_SRC_H 0x824 +#define CX_DST_L 0x828 +#define CX_DST_H 0x82C +#define CX_CONFIG 0x830 +#define AXI_CONFIG 0x834 + +#define CX_LLI_CHAIN_EN 0x2 +#define CCFG_EN 0x1 +#define CCFG_MEM2PER (0x1 << 2) +#define CCFG_PER2MEM (0x2 << 2) +#define CCFG_SRCINCR (0x1 << 31) +#define CCFG_DSTINCR (0x1 << 30) +#define GET_HIGH_32BIT(a) ((u32)((u64)(a) >> 32)) +#define GET_LOW_32BIT(a) ((u32)((u64)(a) & 0xffffffff)) +#define U32_TO_U64(u32h, u32l) ((u64)(u32l) | ((u64)(u32h) << 32)) + +struct hisi_desc_hw { + u64 lli; + u32 reserved1[5]; + u32 count; + u64 saddr; + u64 daddr; + u32 config; + u32 reserved2[3]; +} __aligned(64); + +struct hisi_dma_desc_sw { + struct virt_dma_desc vd; + dma_addr_t desc_hw_lli; + size_t desc_num; + size_t size; + struct hisi_desc_hw desc_hw[0]; +}; + +struct hisi_dma_phy; + +struct hisi_dma_chan { + u32 ccfg; + struct virt_dma_chan vc; + struct hisi_dma_phy *phy; + struct list_head node; + enum dma_transfer_direction dir; + dma_addr_t dev_addr; + enum dma_status status; +}; + +struct hisi_dma_phy { + u32 idx; + void __iomem *base; + struct hisi_dma_chan *vchan; + struct hisi_dma_desc_sw *ds_run; + struct hisi_dma_desc_sw *ds_done; +}; + +struct hisi_dma_dev { + struct dma_device slave; + void __iomem *base; + struct tasklet_struct task; + spinlock_t lock; + struct list_head chan_pending; + struct hisi_dma_phy *phy; + struct hisi_dma_chan *chans; + struct clk *clk; + u32 dma_channels; + u32 dma_requests; + u32 dma_min_chan; +}; + +#define to_hisi_dma(dmadev) container_of(dmadev, struct hisi_dma_dev, slave) + +static struct hisi_dma_chan *to_hisi_chan(struct dma_chan *chan) { + return container_of(chan, struct hisi_dma_chan, vc.chan); +} + +static void hisi_dma_pause_dma(struct hisi_dma_phy *phy, struct hisi_dma_dev *d, bool on) +{ + u32 val = 0; + int timeout; + if (on) { + val = (u32)readl(phy->base + CX_CONFIG); + val |= CCFG_EN; + writel(val, phy->base + CX_CONFIG); + } else { + val = (u32)readl(phy->base + CX_CONFIG); + val &= ~CCFG_EN; + writel(val, phy->base + CX_CONFIG); + /* Wait for channel inactive */ + for (timeout = 2000; timeout > 0; timeout--) { + if (!(BIT(phy->idx) & (u64)readl(d->base + CH_STAT))) + break; + writel(val, phy->base + CX_CONFIG); + udelay(1); + } + + if (timeout == 0) + printk(KERN_ERR ":channel%u timeout waiting for pause, timeout:%d\n", + phy->idx, timeout); + } +} + +static void hisi_dma_terminate_chan(struct hisi_dma_phy *phy, struct hisi_dma_dev *d) +{ + u32 val; + + hisi_dma_pause_dma(phy, d, false); + + val = (u32)0x1 << phy->idx; + writel(val, d->base + INT_TC1_RAW); + writel(val, d->base + INT_ERR1_RAW); + writel(val, d->base + INT_ERR2_RAW); +} + +static void hisi_dma_set_desc(struct hisi_dma_phy *phy, struct hisi_desc_hw *hw) +{ + writel(GET_HIGH_32BIT(hw->lli), phy->base + CX_LLI_H); + writel(GET_LOW_32BIT(hw->lli), phy->base + CX_LLI_L); + writel(hw->count, phy->base + CX_CNT); + writel(GET_HIGH_32BIT(hw->saddr), phy->base + CX_SRC_H); + writel(GET_LOW_32BIT(hw->saddr), phy->base + CX_SRC_L); + writel(GET_HIGH_32BIT(hw->daddr), phy->base + CX_DST_H); + writel(GET_LOW_32BIT(hw->daddr), phy->base + CX_DST_L); + writel(hw->config, phy->base + CX_CONFIG); +} + +static u32 hisi_dma_get_curr_cnt(struct hisi_dma_dev *d, struct hisi_dma_phy *phy) +{ + u32 cnt; + + cnt = (u32)readl(d->base + CX_CUR_CNT + phy->idx * 0x20); + cnt &= 0xffff; + return cnt; +} + +static u64 hisi_dma_get_curr_lli(struct hisi_dma_phy *phy) +{ + return U32_TO_U64(readl(phy->base + CX_LLI_H), readl(phy->base + CX_LLI_L)); +} + +static u32 hisi_dma_get_chan_stat(struct hisi_dma_dev *d) +{ + return readl(d->base + CH_STAT); +} + +static void hisi_dma_enable_dma(struct hisi_dma_dev *d, bool on) +{ + if (on) { + /* set same priority */ + writel(0x0, d ->base + CH_PRI); + + /* unmask irq */ + writel(DMA_CHAN_MASK, d ->base + INT_TC1_MASK); + writel(DMA_CHAN_MASK, d ->base + INT_ERR1_MASK); + writel(DMA_CHAN_MASK, d ->base + INT_ERR2_MASK); + + } else { + /* mask irq */ + writel(0x0, d ->base + INT_TC1_MASK); + writel(0x0, d ->base + INT_ERR1_MASK); + writel(0x0, d ->base + INT_ERR2_MASK); + } +} + +static irqreturn_t hisi_dma_int_handler(int irq, void *dev_id) +{ + struct hisi_dma_dev *d = (struct hisi_dma_dev *)dev_id; + struct hisi_dma_phy *p; + struct hisi_dma_chan *c; + u32 stat = (u32)readl(d->base + INT_STAT); + u32 tc1 = (u32)readl(d->base + INT_TC1); + u32 err1 = (u32)readl(d->base + INT_ERR1); + u32 err2 = (u32)readl(d->base + INT_ERR2); + u32 i, tc1_irq = 0, err1_irq = 0, err2_irq = 0; + u32 stats = stat; + + while (stat) { + i = (u32)__ffs((unsigned long)stat); + stat &= (stat - 1); + if (likely(tc1 & BIT(i))) { + p = &d->phy[i]; + c = p->vchan; + if (c) { + unsigned long flags; + + spin_lock_irqsave(&c->vc.lock, flags); + if(p->ds_run != NULL) + vchan_cookie_complete(&p->ds_run->vd); + p->ds_done = p->ds_run; + spin_unlock_irqrestore(&c->vc.lock, flags); + } else { + dev_err(d->slave.dev, "%s: phy[%d] stats[0x%x]\n", + __func__, p->idx, stats); + } + tc1_irq |= (u32)BIT(i); + } + + if (unlikely((err1 & BIT(i)) || (err2 & BIT(i)))) { + p = &d->phy[i]; + c = p->vchan; + if (c) + c->status = DMA_ERROR; + if(err1 & BIT(i)) + err1_irq |= (u32)BIT(i); + if(err2 & BIT(i)) + err2_irq |= (u32)BIT(i); + dev_warn(d->slave.dev, "DMA ERR phy[%d] stats[0x%x] err1[0x%x] err2[0x%x]\n", + p->idx, stats, err1, err2); + } + + } + + writel(tc1_irq, d->base + INT_TC1_RAW); + writel(err1_irq, d->base + INT_ERR1_RAW); + writel(err2_irq, d->base + INT_ERR2_RAW); + + if (tc1_irq || err1_irq || err2_irq) { + tasklet_schedule(&d->task); + + return IRQ_HANDLED; + } else + return IRQ_NONE; +} + +static int hisi_dma_start_txd(struct hisi_dma_chan *c) +{ + struct hisi_dma_dev *d = to_hisi_dma(c->vc.chan.device); + struct virt_dma_desc *vd = vchan_next_desc(&c->vc); + + + if (!c->phy) + return -ENODEV; + + if (BIT(c->phy->idx) & hisi_dma_get_chan_stat(d)) { + dev_err(d->slave.dev, "%s: chan[%d] phy[%d] stat[0x%x]\n", __func__, + c->vc.chan.chan_id, c->phy->idx, hisi_dma_get_chan_stat(d)); + return -EBUSY; + } + + if (vd) { + struct hisi_dma_desc_sw *ds = + container_of(vd, struct hisi_dma_desc_sw, vd); + + /* + * fetch and remove request from vc->desc_issued + * so vc->desc_issued only contains desc pending + */ + list_del(&ds->vd.node); + c->phy->ds_run = ds; + c->phy->ds_done = NULL; + /* start dma */ + hisi_dma_set_desc(c->phy, &ds->desc_hw[0]); + + return 0; + } + c->phy->ds_done = NULL; + c->phy->ds_run = NULL; + return -EAGAIN; +} + +static void hisi_dma_tasklet(unsigned long arg) +{ + struct hisi_dma_dev *d = (struct hisi_dma_dev *)arg; + struct hisi_dma_phy *p; + struct hisi_dma_chan *c, *cn; + unsigned pch, pch_alloc = 0; + unsigned long flags; + int ret = 0; + + /* check new dma request of running channel in vc->desc_issued */ + list_for_each_entry_safe(c, cn, &d->slave.channels, vc.chan.device_node) { + spin_lock_irqsave(&c->vc.lock,flags); + p = c->phy; + + if (p && p->ds_done) { + ret = hisi_dma_start_txd(c); + if (-EAGAIN == ret) { + /* No current txd associated with this channel */ + dev_dbg(d->slave.dev, "pchan %u: free\n", p->idx); + /* Mark this channel free */ + c->phy = NULL; + p->vchan = NULL; + } else if (0 != ret) { + continue; + } + } else if(p && c->status == DMA_ERROR) { + hisi_dma_terminate_chan(p, d); + c->phy = NULL; + p->vchan = NULL; + p->ds_run = p->ds_done = NULL; + } + + spin_unlock_irqrestore(&c->vc.lock,flags); + } + + /* check new channel request in d->chan_pending */ + spin_lock_irqsave(&d->lock,flags); + + for (pch = d->dma_min_chan; pch < d->dma_channels; pch++) { + p = &d->phy[pch]; + + if (p->vchan == NULL && !list_empty(&d->chan_pending)) { + c = list_first_entry(&d->chan_pending, + struct hisi_dma_chan, node); + /* remove from d->chan_pending */ + list_del_init(&c->node); + pch_alloc |= (u32)1 << pch; + /* Mark this channel allocated */ + p->vchan = c; + c->phy = p; + dev_dbg(d->slave.dev, "pchan %u: alloc vchan %pK\n", pch, &c->vc); + } + } + spin_unlock_irqrestore(&d->lock,flags); + + for (pch = d->dma_min_chan; pch < d->dma_channels; pch++) { + if (pch_alloc & ((u32)1 << pch)) { + + p = &d->phy[pch]; + c = p->vchan; + if (c) { + spin_lock_irqsave(&c->vc.lock,flags); + hisi_dma_start_txd(c); + spin_unlock_irqrestore(&c->vc.lock,flags); + } + } + } +} + +static int hisi_dma_alloc_chan_resources(struct dma_chan *chan) +{ + return 0; +} + +static void hisi_dma_free_chan_resources(struct dma_chan *chan) +{ + struct hisi_dma_chan *c = to_hisi_chan(chan); + struct hisi_dma_dev *d = to_hisi_dma(chan->device); + unsigned long flags; + + spin_lock_irqsave(&d->lock, flags); + list_del_init(&c->node); + spin_unlock_irqrestore(&d->lock, flags); + + vchan_free_chan_resources(&c->vc); + c->ccfg = 0; +} + +static enum dma_status hisi_dma_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, struct dma_tx_state *state) +{ + struct hisi_dma_chan *c = to_hisi_chan(chan); + struct hisi_dma_dev *d = to_hisi_dma(chan->device); + struct hisi_dma_phy *p; + struct virt_dma_desc *vd; + unsigned long flags; + enum dma_status ret; + size_t bytes = 0; + + ret = dma_cookie_status(&c->vc.chan, cookie, state); + if (ret == DMA_COMPLETE) + return ret; + + spin_lock_irqsave(&c->vc.lock, flags); + p = c->phy; + ret = c->status; + + /* + * If the cookie is on our issue queue, then the residue is + * its total size. + */ + vd = vchan_find_desc(&c->vc, cookie); + if (vd) { + bytes = container_of(vd, struct hisi_dma_desc_sw, vd)->size; + } else if ((!p) || (!p->ds_run)) { + bytes = 0; + } else { + struct hisi_dma_desc_sw *ds = p->ds_run; + u64 clli, index; + + bytes = hisi_dma_get_curr_cnt(d, p); + clli = hisi_dma_get_curr_lli(p); + index = (clli - ds->desc_hw_lli) / sizeof(struct hisi_desc_hw); + for (; index < ds->desc_num; index++) { + bytes += ds->desc_hw[index].count; + /* end of lli */ + if (!ds->desc_hw[index].lli) + break; + } + } + spin_unlock_irqrestore(&c->vc.lock, flags); + dma_set_residue(state, (u32)bytes); + return ret; +} + +static void hisi_dma_issue_pending(struct dma_chan *chan) +{ + struct hisi_dma_chan *c = to_hisi_chan(chan); + struct hisi_dma_dev *d = to_hisi_dma(chan->device); + unsigned long flags; + + spin_lock_irqsave(&c->vc.lock, flags); + /* add request to vc->desc_issued */ + if (vchan_issue_pending(&c->vc)) { + spin_lock(&d->lock); + if (!c->phy) { + if (list_empty(&c->node)) { + /* if new channel, add chan_pending */ + list_add_tail(&c->node, &d->chan_pending); + /* check in tasklet */ + tasklet_schedule(&d->task); + dev_dbg(d->slave.dev, "vchan %pK: issued\n", &c->vc); + } + } + spin_unlock(&d->lock); + } else + dev_dbg(d->slave.dev, "vchan %pK: nothing to issue\n", &c->vc); + spin_unlock_irqrestore(&c->vc.lock, flags); +} + +static void hisi_dma_fill_desc(struct hisi_dma_desc_sw *ds, dma_addr_t dst, + dma_addr_t src, size_t len, u32 num, u32 ccfg) +{ + if ((num + 1) < ds->desc_num) + ds->desc_hw[num].lli = ds->desc_hw_lli + (u64)(num + 1) * + sizeof(struct hisi_desc_hw); + ds->desc_hw[num].lli |= CX_LLI_CHAIN_EN; + ds->desc_hw[num].count = (u32)len; + ds->desc_hw[num].saddr = src; + ds->desc_hw[num].daddr = dst; + ds->desc_hw[num].config = ccfg; +} + +static struct dma_async_tx_descriptor *hisi_dma_prep_memcpy( + struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, + size_t len, unsigned long flags) { + struct hisi_dma_chan *c = to_hisi_chan(chan); + struct hisi_dma_desc_sw *ds; + size_t copy = 0; + u32 num; + + if (!len) + return NULL; + + num = (u32)DIV_ROUND_UP(len, DMA_MAX_SIZE); + ds = kzalloc(sizeof(*ds) + num * sizeof(ds->desc_hw[0]), GFP_ATOMIC | GFP_DMA); + if (!ds) { + dev_dbg(chan->device->dev, "vchan %pK: kzalloc fail\n", (void*)&c->vc); + return NULL; + } + ds->desc_hw_lli = __virt_to_phys((unsigned long)&ds->desc_hw[0]); + ds->size = len; + ds->desc_num = (size_t)num; + num = 0; + + if (!c->ccfg) { + /* default is memtomem, without calling device_control */ + c->ccfg = CCFG_SRCINCR | CCFG_DSTINCR | CCFG_EN; + c->ccfg |= (0xf << 20) | (0xf << 24); /* burst = 16 */ + c->ccfg |= (0x3 << 12) | (0x3 << 16); /* width = 64 bit */ + } + + do { + copy = min_t(size_t, len, DMA_MAX_SIZE); + hisi_dma_fill_desc(ds, dst, src, copy, num++, c->ccfg); + + if (c->dir == DMA_MEM_TO_DEV) { + src += copy; + } else if (c->dir == DMA_DEV_TO_MEM) { + dst += copy; + } else { + src += copy; + dst += copy; + } + len -= copy; + } while (len); + + ds->desc_hw[num-1].lli = 0; /* end of link */ + + return vchan_tx_prep(&c->vc, &ds->vd, flags); +} + +static struct dma_async_tx_descriptor *hisi_dma_prep_slave_sg( + struct dma_chan *chan, struct scatterlist *sgl, unsigned int sglen, + enum dma_transfer_direction dir, unsigned long flags, void *context) { + struct hisi_dma_chan *c = to_hisi_chan(chan); + struct hisi_dma_desc_sw *ds; + size_t len, avail, total = 0; + struct scatterlist *sg; + dma_addr_t addr, src = 0, dst = 0; + u32 num = sglen, i; + + if (sgl == NULL) + return NULL; + + for_each_sg(sgl, sg, sglen, i) { + avail = sg_dma_len(sg); + if (avail > DMA_MAX_SIZE) + num += (u32)DIV_ROUND_UP(avail, DMA_MAX_SIZE) - 1; + } + + ds = kzalloc(sizeof(*ds) + num * sizeof(ds->desc_hw[0]), GFP_ATOMIC | GFP_DMA); + if (!ds) { + dev_dbg(chan->device->dev, "vchan %pK: kzalloc fail\n", &c->vc); + return NULL; + } + ds->desc_hw_lli = __virt_to_phys((unsigned long)&ds->desc_hw[0]); + ds->desc_num = num; + num = 0; + + for_each_sg(sgl, sg, sglen, i) { + addr = sg_dma_address(sg); + avail = sg_dma_len(sg); + total += avail; + + do { + len = min_t(size_t, avail, DMA_MAX_SIZE); + + if (dir == DMA_MEM_TO_DEV) { + src = addr; + dst = c->dev_addr; + } else if (dir == DMA_DEV_TO_MEM) { + src = c->dev_addr; + dst = addr; + } + + hisi_dma_fill_desc(ds, dst, src, len, num++, c->ccfg); + + addr += len; + avail -= len; + } while (avail); + } + + ds->desc_hw[(int)num-1].lli = 0; /* end of link */ + + ds->size = total; + return vchan_tx_prep(&c->vc, &ds->vd, flags); +} + +static int hisi_dma_config(struct dma_chan *chan, struct dma_slave_config *config) +{ + struct hisi_dma_chan *c = to_hisi_chan(chan); + struct hisi_dma_dev *d = to_hisi_dma(chan->device); + u32 maxburst = 0, val = 0; + enum dma_slave_buswidth width = DMA_SLAVE_BUSWIDTH_UNDEFINED; + + if (NULL == c) { + dev_warn(d->slave.dev, "vchan is NULL\n"); + return -EINVAL; + } + + if (config == NULL) + return -EINVAL; + c->dir = config->direction; + if (c->dir == DMA_DEV_TO_MEM) { + c->ccfg = CCFG_DSTINCR; + c->dev_addr = config->src_addr; + maxburst = config->src_maxburst; + width = config->src_addr_width; + } else if (c->dir == DMA_MEM_TO_DEV) { + c->ccfg = CCFG_SRCINCR; + c->dev_addr = config->dst_addr; + maxburst = config->dst_maxburst; + width = config->dst_addr_width; + } else if(c->dir == DMA_MEM_TO_MEM) { + c->ccfg = CCFG_SRCINCR | CCFG_DSTINCR; + } + + switch (width) { + case DMA_SLAVE_BUSWIDTH_1_BYTE: + val = 0; + break; + case DMA_SLAVE_BUSWIDTH_2_BYTES: + val = 1; + break; + case DMA_SLAVE_BUSWIDTH_4_BYTES: + val = 2; + break; + case DMA_SLAVE_BUSWIDTH_8_BYTES: + val = 3; + break; + default: + break; + } + c->ccfg |= (val << 12) | (val << 16); + + if ((maxburst == 0) || (maxburst > 16)) + val = 16; + else + val = maxburst - 1; + c->ccfg |= (val << 20) | (val << 24); + c->ccfg |= CCFG_MEM2PER | CCFG_EN; + + /* specific request line */ + c->ccfg |= (u32)c->vc.chan.chan_id << 4; + return 0; +} + +static int hisi_dma_pause(struct dma_chan *chan) +{ + struct hisi_dma_chan *c = to_hisi_chan(chan); + struct hisi_dma_dev *d = to_hisi_dma(chan->device); + unsigned long flags; + struct hisi_dma_phy *p = NULL; + + if (NULL == c) { + dev_warn(d->slave.dev, "vchan is NULL\n"); + return -EINVAL; + } + + dev_dbg(d->slave.dev, "vchan %pK: pause\n", &c->vc); + if (c->status == DMA_IN_PROGRESS) { + c->status = DMA_PAUSED; + spin_lock_irqsave(&d->lock,flags); + p = c->phy; + if (p) { + spin_unlock_irqrestore(&d->lock,flags); + hisi_dma_pause_dma(p, d, false); + } else { + list_del_init(&c->node); + spin_unlock_irqrestore(&d->lock,flags); + } + } + return 0; +} + +static int hisi_dma_resume(struct dma_chan *chan) +{ + struct hisi_dma_chan *c = to_hisi_chan(chan); + struct hisi_dma_dev *d = to_hisi_dma(chan->device); + unsigned long flags; + struct hisi_dma_phy *p; + + if (NULL == c) { + dev_warn(d->slave.dev, "vchan is NULL\n"); + return -EINVAL; + } + + dev_dbg(d->slave.dev, "vchan %pK: resume\n", &c->vc); + spin_lock_irqsave(&c->vc.lock, flags); + p = c->phy; + if (c->status == DMA_PAUSED) { + c->status = DMA_IN_PROGRESS; + if (p) { + hisi_dma_pause_dma(p, d, true); + } else if (!list_empty(&c->vc.desc_issued)) { + spin_lock(&d->lock); + list_add_tail(&c->node, &d->chan_pending); + spin_unlock(&d->lock); + } + } + spin_unlock_irqrestore(&c->vc.lock, flags); + return 0; +} + +static int hisi_dma_terminate_all(struct dma_chan *chan) +{ + struct hisi_dma_chan *c = to_hisi_chan(chan); + struct hisi_dma_dev *d = to_hisi_dma(chan->device); + unsigned long flags; + struct hisi_dma_phy *p; + LIST_HEAD(head); + + if (NULL == c) { + dev_warn(d->slave.dev, "vchan is NULL\n"); + return -EINVAL; + } + + dev_dbg(d->slave.dev, "vchan %pK: terminate all\n", &c->vc); + /* Prevent this channel being scheduled */ + spin_lock_irqsave(&d->lock,flags); + list_del_init(&c->node); + spin_unlock_irqrestore(&d->lock,flags); + + /* Clear the tx descriptor lists */ + spin_lock_irqsave(&c->vc.lock, flags); + p = c->phy; + vchan_get_all_descriptors(&c->vc, &head); + if(p && p->ds_run != NULL && p->ds_done == NULL) { + list_add_tail(&p->ds_run->vd.node, &head); + } + + if (p) { + /* vchan is assigned to a pchan - stop the channel */ + hisi_dma_terminate_chan(p, d); + c->phy = NULL; + p->vchan = NULL; + p->ds_run = p->ds_done = NULL; + } + spin_unlock_irqrestore(&c->vc.lock, flags); + vchan_dma_desc_free_list(&c->vc, &head); + + return 0; +} + +static void hisi_dma_free_desc(struct virt_dma_desc *vd) +{ + struct hisi_dma_desc_sw *ds = + container_of(vd, struct hisi_dma_desc_sw, vd); + + kfree(ds); +} + +static struct of_device_id hisi_pdma64_dt_ids[] = { + { .compatible = "hisilicon,hisi-dma64-1.0", }, + {} +}; +MODULE_DEVICE_TABLE(of, hisi_pdma64_dt_ids); + +static struct dma_chan *hisi_of_dma_simple_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) { + struct hisi_dma_dev *d = ofdma->of_dma_data; + unsigned int request = dma_spec->args[0]; + + if (request > d->dma_requests) + return NULL; + + return dma_get_slave_channel(&(d->chans[request].vc.chan)); +} + +static int hisi_dma_probe(struct platform_device *op) +{ + struct hisi_dma_dev *d; + const struct of_device_id *of_id; + struct resource *iores; + u32 i, irq; + int ret = 0; + + iores = platform_get_resource(op, IORESOURCE_MEM, 0); + if (!iores) + return -EINVAL; + + d = devm_kzalloc(&op->dev, sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; + + d->base = devm_ioremap_resource(&op->dev, iores); + if (!d->base) + return -EADDRNOTAVAIL; + + of_id = of_match_device(hisi_pdma64_dt_ids, &op->dev); + if (of_id) { + ret = of_property_read_u32((&op->dev)->of_node, + "dma-channels", &d->dma_channels); + } + if (ret) { + dev_err(&op->dev,"%s doesn't have dma-channels property!\n", + __func__); + return ret; + } + ret = of_property_read_u32((&op->dev)->of_node, + "dma-requests", &d->dma_requests); + if (ret) { + dev_err(&op->dev,"%s doesn't have dma-request property!\n", + __func__); + return ret; + } + + of_property_read_u32((&op->dev)->of_node, + "dma-min-chan", &d->dma_min_chan); + + dev_info(&op->dev, "dma_channels:0x%x dma_requests:0x%x dma_min_chan:0x%x \n", + d->dma_channels,d->dma_requests,d->dma_min_chan); + + op->dev.dma_mask = &(op->dev.coherent_dma_mask); + op->dev.coherent_dma_mask = DMA_BIT_MASK(64); + + d->clk = devm_clk_get(&op->dev, NULL); + if (IS_ERR(d->clk)) { + dev_err(&op->dev, "no dma clk\n"); + return (int)PTR_ERR(d->clk); + } + + irq = (u32)platform_get_irq(op, 0); + ret = devm_request_irq(&op->dev, irq, + hisi_dma_int_handler, 0, DRIVER_NAME, d); + if (ret) + return ret; + + /* init phy channel */ + d->phy = devm_kzalloc(&op->dev, + d->dma_channels * sizeof(struct hisi_dma_phy), GFP_KERNEL); + if (d->phy == NULL) + return -ENOMEM; + + for (i = d->dma_min_chan; i < d->dma_channels; i++) { + struct hisi_dma_phy *p = &d->phy[i]; + p->idx = i; + p->base = d->base + i * 0x40; + } + + INIT_LIST_HEAD(&d->slave.channels); + dma_cap_set(DMA_SLAVE, d->slave.cap_mask); + dma_cap_set(DMA_MEMCPY, d->slave.cap_mask); + dma_cap_set(DMA_PRIVATE, d->slave.cap_mask); + op->dev.coherent_dma_mask = DMA_BIT_MASK(64); + op->dev.dma_mask = &op->dev.coherent_dma_mask; + d->slave.dev = &op->dev; + d->slave.device_alloc_chan_resources = hisi_dma_alloc_chan_resources; + d->slave.device_free_chan_resources = hisi_dma_free_chan_resources; + d->slave.device_tx_status = hisi_dma_tx_status; + d->slave.device_prep_dma_memcpy = hisi_dma_prep_memcpy; + d->slave.device_prep_slave_sg = hisi_dma_prep_slave_sg; + d->slave.device_issue_pending = hisi_dma_issue_pending; + d->slave.device_config = hisi_dma_config; + d->slave.device_pause = hisi_dma_pause; + d->slave.device_resume = hisi_dma_resume; + d->slave.device_terminate_all = hisi_dma_terminate_all; + d->slave.copy_align = DMA_ALIGN; + d->slave.chancnt = d->dma_requests; + + /* init virtual channel */ + d->chans = devm_kzalloc(&op->dev, + d->dma_requests * sizeof(struct hisi_dma_chan), GFP_KERNEL); + if (d->chans == NULL) + return -ENOMEM; + + for (i = 0; i < d->dma_requests; i++) { + struct hisi_dma_chan *c = &d->chans[i]; + + c->status = DMA_IN_PROGRESS; + INIT_LIST_HEAD(&c->node); + c->vc.desc_free = hisi_dma_free_desc; + vchan_init(&c->vc, &d->slave); + } + + /* Enable clock before accessing registers */ + ret = clk_prepare_enable(d->clk); + if (ret < 0) { + dev_err(&op->dev, "clk_prepare_enable failed: %d\n", ret); + return -EINVAL; + } + hisi_dma_enable_dma(d, true); + + ret = dma_async_device_register(&d->slave); + if (ret) + return ret; + + ret = of_dma_controller_register((&op->dev)->of_node, + hisi_of_dma_simple_xlate, d); + if (ret) + goto of_dma_register_fail; + + spin_lock_init(&d->lock); + INIT_LIST_HEAD(&d->chan_pending); + tasklet_init(&d->task, hisi_dma_tasklet, (unsigned long)d); + platform_set_drvdata(op, d); + dev_info(&op->dev, "initialized\n"); + + + dev_info(&op->dev, "hisi_dma64_probe ok!\n"); + + return 0; + +of_dma_register_fail: + dma_async_device_unregister(&d->slave); + return ret; +} + +static int hisi_dma_remove(struct platform_device *op) +{ + struct hisi_dma_chan *c, *cn; + struct hisi_dma_dev *d = platform_get_drvdata(op); + + if (!d){ + pr_err("%s: get drvdata failed\n", __func__); + return -EINVAL; + } + + dma_async_device_unregister(&d->slave); + of_dma_controller_free((&op->dev)->of_node); + + list_for_each_entry_safe(c, cn, &d->slave.channels, vc.chan.device_node) { + list_del(&c->vc.chan.device_node); + tasklet_kill(&c->vc.task); + } + tasklet_kill(&d->task); + + clk_disable_unprepare(d->clk); + + return 0; +} + +#if defined(CONFIG_PM_SLEEP) +static int hisi_dma_pltfm_suspend(struct device *dev) +{ + struct hisi_dma_dev *d = dev_get_drvdata(dev); + u32 stat; + u32 limit = 500; + + if (!d){ + pr_err("%s: get drvdata failed\n", __func__); + return -EINVAL; + } + + dev_info(d->slave.dev, "%s: suspend +\n", __func__); + pm_runtime_get_sync(d->slave.dev); + + stat = hisi_dma_get_chan_stat(d); + stat = stat & DMA_CHAN_MASK; + + while ( (stat) && limit--) { + udelay(1000); + stat = hisi_dma_get_chan_stat(d); + stat = stat & DMA_CHAN_MASK; + } + + if (stat) { + dev_warn(d->slave.dev,"chan 0x%x is running fail to suspend\n", stat); + { + u32 i; + for(i = d->dma_min_chan; i < d->dma_channels; i++) { + dev_warn(d->slave.dev,"chanel:%d, CX_CONFIG: 0x%x, CX_AXI_CONF: 0x%x\n",i, + readl(d->base + CX_CONFIG + i*0x40), readl(d->base + AXI_CONFIG + i*0x40)); + } + } + return -1; + } + + hisi_dma_enable_dma(d, false); + + clk_disable(d->clk); + + pm_runtime_put_sync(d->slave.dev); + dev_info(d->slave.dev, "%s: suspend -\n", __func__); + return 0; +} + +static int hisi_dma_pltfm_resume(struct device *dev) +{ + struct hisi_dma_dev *d = dev_get_drvdata(dev); + int ret = 0; + + if (!d){ + pr_err("%s: get drvdata failed\n", __func__); + return -EINVAL; + } + + dev_info(d->slave.dev, "%s: resume +\n", __func__); + pm_runtime_get_sync(d->slave.dev); + + + ret = clk_enable(d->clk); + if (ret < 0) { + dev_err(d->slave.dev, "clk_prepare_enable failed: %d\n", ret); + return -EINVAL; + } + + hisi_dma_enable_dma(d, true); + + pm_runtime_put_sync(d->slave.dev); + dev_info(d->slave.dev, "%s: resume -\n", __func__); + return 0; +} +#else +#define hisi_dma_pltfm_suspend NULL +#define hisi_dma_pltfm_resume NULL +#endif /* CONFIG_PM_SLEEP*/ + +//SIMPLE_DEV_PM_OPS(hisi_dma_pltfm_pmops, hisi_dma_pltfm_suspend, hisi_dma_pltfm_resume); + + +const struct dev_pm_ops hisi_dma64_pm_ops = { + .suspend_late = hisi_dma_pltfm_suspend, + .resume_early = hisi_dma_pltfm_resume, +}; + + +static struct platform_driver hisi_pdma64_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .pm = &hisi_dma64_pm_ops, + .of_match_table = hisi_pdma64_dt_ids, + }, + .probe = hisi_dma_probe, + .remove = hisi_dma_remove, +}; + +static int __init dmac_module_init(void) +{ + int retval; + + retval = platform_driver_register(&hisi_pdma64_driver); + if (retval) { + printk(KERN_ERR "hisidma platform driver register failed\n"); + return retval; + } + + return retval; +} + +static void __exit dmac_module_exit(void) +{ + platform_driver_unregister(&hisi_pdma64_driver); +} + +arch_initcall(dmac_module_init); +MODULE_DESCRIPTION("Hisilicon hisi 64bit DMA Driver"); +MODULE_LICENSE("GPL v2"); +