@@ -3,3 +3,8 @@
#@DESCRIPTION: Machine configuration for Corstone700 FVP
require conf/machine/include/corstone700.inc
+
+# default feature used: eth_lan91c111
+# add the following line to local.conf to disable the feature:
+# MACHINE_FEATURES_remove = "eth_lan91c111"
+MACHINE_FEATURES += "eth_lan91c111"
new file mode 100644
@@ -0,0 +1,6 @@
+define KMACHINE corstone700
+define KTYPE standard
+define KARCH arm
+
+kconf hardware corstone700/base.cfg
+kconf hardware corstone700/xip.cfg
new file mode 100644
@@ -0,0 +1,35 @@
+CONFIG_LOCALVERSION="-yocto-standard"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_LOG_BUF_SHIFT=12
+# CONFIG_UTS_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_ARM_SINGLE_ARMV7A=y
+CONFIG_ARCH_TINY_VEXPRESS=y
+CONFIG_HAVE_ARM_ARCH_TIMER=y
+CONFIG_THUMB2_KERNEL=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_VFP=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
+CONFIG_TMPFS=y
+CONFIG_EXTSYS_CTRL=y
+# CONFIG_WLAN is not set
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_PL031=y
+CONFIG_MAILBOX=y
+CONFIG_ARM_MHUv2=y
+CONFIG_RPMSG_CHAR=y
+CONFIG_RPMSG_ARM=y
+# CONFIG_CRYPTO_HW is not set
new file mode 100644
@@ -0,0 +1,4 @@
+define KFEATURE_DESCRIPTION "Ethernet feature using lan91c111"
+
+kconf hardware pnp.cfg
+kconf hardware lan91c111.cfg
\ No newline at end of file
new file mode 100644
@@ -0,0 +1 @@
+CONFIG_SMC91X=y
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,4 @@
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_NETDEVICES=y
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,12 @@
+CONFIG_PHYS_OFFSET=0x80000000
+CONFIG_XIP_KERNEL=y
+CONFIG_XIP_PHYS_ADDR=0x08300000
+CONFIG_MTD=y
+CONFIG_MTD_RAM=y
+CONFIG_MTD_ROM=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_COMPAT=y
+CONFIG_MTD_PHYSMAP_START=0x08100000
+CONFIG_MTD_PHYSMAP_LEN=0x200000
+CONFIG_CRAMFS=y
+CONFIG_CRAMFS_MTD=y
new file mode 100644
@@ -0,0 +1,3 @@
+CONFIG_CMDLINE="console=ttyAMA0 root=mtd:physmap-flash.0 ro loglevel=9"
+# CONFIG_CMDLINE_FROM_BOOTLOADER is not set
+CONFIG_CMDLINE_EXTEND=y
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,3 @@
+CONFIG_CMDLINE="console=ttyAMA0 root=mtd:physmap-flash.0 ro ip=dhcp loglevel=9"
+# CONFIG_CMDLINE_FROM_BOOTLOADER is not set
+CONFIG_CMDLINE_EXTEND=y
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,97 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+
+From faac2fbc88b932b79b33b7299116d269d1167a18 Mon Sep 17 00:00:00 2001
+From: Manish Pandey <manish.pandey2@arm.com>
+Date: Mon, 18 Jun 2018 13:00:31 +0100
+Subject: [PATCH 01/20] arm: support for a single ARMv7-A based platform.
+
+The reason for having a single ARMv7A based platform is to bypass
+collection of configs provided/concealed by ARCH_MULTIPLATFORM, for
+example XIP_KERNEL cannot be enabled with ARCH_MULTIPLATFORM.
+
+Having a separate config for single ARMv7-A platform will give the
+freedom to choose only those configs which are required for a given
+ARMv7-A based platform.
+
+Signed-off-by: Manish Pandey <manish.pandey2@arm.com>
+Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
+---
+ arch/arm/Kconfig | 14 ++++++++++++++
+ arch/arm/Kconfig.debug | 3 ++-
+ arch/arm/Makefile | 2 ++
+ arch/arm/kernel/devtree.c | 3 ++-
+ 4 files changed, 20 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index 97864aabc2a6..04db53ed23fc 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -338,6 +338,20 @@ config ARM_SINGLE_ARMV7M
+ select SPARSE_IRQ
+ select USE_OF
+
++config ARM_SINGLE_ARMV7A
++ bool "ARMv7-A single platform"
++ select ARM_HAS_SG_CHAIN
++ select AUTO_ZRELADDR
++ select TIMER_OF
++ select COMMON_CLK
++ select CPU_V7
++ select GENERIC_CLOCKEVENTS
++ select MIGHT_HAVE_PCI
++ select MULTI_IRQ_HANDLER
++ select PCI_DOMAINS if PCI
++ select SPARSE_IRQ
++ select USE_OF
++
+ config ARCH_EBSA110
+ bool "EBSA-110"
+ select ARCH_USES_GETTIMEOFFSET
+diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
+index b70d7debf5ca..592f5d7aa412 100644
+--- a/arch/arm/Kconfig.debug
++++ b/arch/arm/Kconfig.debug
+@@ -1878,7 +1878,8 @@ config DEBUG_UNCOMPRESS
+ config UNCOMPRESS_INCLUDE
+ string
+ default "debug/uncompress.h" if ARCH_MULTIPLATFORM || ARCH_MSM || \
+- PLAT_SAMSUNG || ARM_SINGLE_ARMV7M
++ PLAT_SAMSUNG || ARM_SINGLE_ARMV7M || \
++ ARM_SINGLE_ARMV7A
+ default "mach/uncompress.h"
+
+ config EARLY_PRINTK
+diff --git a/arch/arm/Makefile b/arch/arm/Makefile
+index 1fc32b611f8a..fa1519959f6a 100644
+--- a/arch/arm/Makefile
++++ b/arch/arm/Makefile
+@@ -267,9 +267,11 @@ platdirs := $(patsubst %,arch/arm/plat-%/,$(sort $(plat-y)))
+
+ ifneq ($(CONFIG_ARCH_MULTIPLATFORM),y)
+ ifneq ($(CONFIG_ARM_SINGLE_ARMV7M),y)
++ifneq ($(CONFIG_ARM_SINGLE_ARMV7A),y)
+ KBUILD_CPPFLAGS += $(patsubst %,-I$(srctree)/%include,$(machdirs) $(platdirs))
+ endif
+ endif
++endif
+
+ export TEXT_OFFSET GZFLAGS MMUEXT
+
+diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c
+index 39c978698406..88e9f22a6778 100644
+--- a/arch/arm/kernel/devtree.c
++++ b/arch/arm/kernel/devtree.c
+@@ -212,7 +212,8 @@ const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
+ {
+ const struct machine_desc *mdesc, *mdesc_best = NULL;
+
+-#if defined(CONFIG_ARCH_MULTIPLATFORM) || defined(CONFIG_ARM_SINGLE_ARMV7M)
++#if defined(CONFIG_ARCH_MULTIPLATFORM) || defined(CONFIG_ARM_SINGLE_ARMV7M)\
++ || defined(CONFIG_ARM_SINGLE_ARMV7A)
+ DT_MACHINE_START(GENERIC_DT, "Generic DT based system")
+ .l2c_aux_val = 0x0,
+ .l2c_aux_mask = ~0x0,
+--
+2.17.1
+
new file mode 100644
@@ -0,0 +1,101 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+
+From f984be4e9b113b0c92ae2b618381f0499bf41865 Mon Sep 17 00:00:00 2001
+From: Manish Pandey <manish.pandey2@arm.com>
+Date: Mon, 18 Jun 2018 13:04:31 +0100
+Subject: [PATCH 02/20] arm: Add tiny vexpress machine.
+
+added tiny vexpress machine which is cut down version of
+vexpress machine and intended to be used for IOT devices.
+
+Signed-off-by: Manish Pandey <manish.pandey2@arm.com>
+Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
+---
+ arch/arm/Kconfig | 2 ++
+ arch/arm/mach-tinyexpress/Kconfig | 28 ++++++++++++++++++++++++++++
+ drivers/clk/versatile/Kconfig | 6 +++---
+ 3 files changed, 33 insertions(+), 3 deletions(-)
+ create mode 100644 arch/arm/mach-tinyexpress/Kconfig
+
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index 04db53ed23fc..ef49bbc9d5e2 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -752,6 +752,8 @@ source "arch/arm/mach-versatile/Kconfig"
+ source "arch/arm/mach-vexpress/Kconfig"
+ source "arch/arm/plat-versatile/Kconfig"
+
++source "arch/arm/mach-tinyexpress/Kconfig"
++
+ source "arch/arm/mach-vt8500/Kconfig"
+
+ source "arch/arm/mach-zx/Kconfig"
+diff --git a/arch/arm/mach-tinyexpress/Kconfig b/arch/arm/mach-tinyexpress/Kconfig
+new file mode 100644
+index 000000000000..f9946bad1170
+--- /dev/null
++++ b/arch/arm/mach-tinyexpress/Kconfig
+@@ -0,0 +1,28 @@
++config ARCH_TINY_VEXPRESS
++ bool "ARM Ltd. Tiny Versatile Express family"
++ depends on ARM_SINGLE_ARMV7A
++ select ARCH_SUPPORTS_BIG_ENDIAN
++ select ARM_AMBA
++ select ARM_GIC
++ select ARM_GLOBAL_TIMER
++ select ARM_TIMER_SP804
++ select COMMON_CLK_VERSATILE
++ select GPIOLIB
++ select HAVE_ARM_SCU if SMP
++ select HAVE_ARM_TWD if SMP
++ select HAVE_PATA_PLATFORM
++ select ICST
++ select NO_IOPORT_MAP
++ select PLAT_VERSATILE
++ select POWER_RESET
++ select POWER_RESET_VEXPRESS
++ select POWER_SUPPLY
++ select REGULATOR if MMC_ARMMMCI
++ select REGULATOR_FIXED_VOLTAGE if REGULATOR
++ select VEXPRESS_CONFIG
++ select VEXPRESS_SYSCFG
++ select MFD_VEXPRESS_SYSREG
++ help
++ This option enables support for tiny linux based systems using Cortex
++ processor based ARM core and logic (FPGA) tiles on the Versatile
++ Express motherboard.
+diff --git a/drivers/clk/versatile/Kconfig b/drivers/clk/versatile/Kconfig
+index c2618f1477a2..f245f520df0c 100644
+--- a/drivers/clk/versatile/Kconfig
++++ b/drivers/clk/versatile/Kconfig
+@@ -6,7 +6,7 @@ config COMMON_CLK_VERSATILE
+ bool "Clock driver for ARM Reference designs"
+ depends on ARCH_INTEGRATOR || ARCH_REALVIEW || \
+ ARCH_VERSATILE || ARCH_VEXPRESS || ARM64 || \
+- COMPILE_TEST
++ ARCH_TINY_VEXPRESS || COMPILE_TEST
+ select REGMAP_MMIO
+ ---help---
+ Supports clocking on ARM Reference designs:
+@@ -17,7 +17,7 @@ config COMMON_CLK_VERSATILE
+ config CLK_SP810
+ bool "Clock driver for ARM SP810 System Controller"
+ depends on COMMON_CLK_VERSATILE
+- default y if ARCH_VEXPRESS
++ default y if ARCH_VEXPRESS || ARCH_TINY_VEXPRESS
+ ---help---
+ Supports clock muxing (REFCLK/TIMCLK to TIMERCLKEN0-3) capabilities
+ of the ARM SP810 System Controller cell.
+@@ -26,7 +26,7 @@ config CLK_VEXPRESS_OSC
+ bool "Clock driver for Versatile Express OSC clock generators"
+ depends on COMMON_CLK_VERSATILE
+ depends on VEXPRESS_CONFIG
+- default y if ARCH_VEXPRESS
++ default y if ARCH_VEXPRESS || ARCH_TINY_VEXPRESS
+ ---help---
+ Simple regmap-based driver driving clock generators on Versatile
+ Express platforms hidden behind its configuration infrastructure,
+--
+2.17.1
+
new file mode 100644
@@ -0,0 +1,197 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+
+From f237b4ab421bae452a8613d6343d7e35d1295003 Mon Sep 17 00:00:00 2001
+From: Manish Pandey <manish.pandey2@arm.com>
+Date: Tue, 15 Jan 2019 16:21:20 +0000
+Subject: [PATCH 03/20] arm: introduce corstone700_defconfig
+
+corstone700_defconfig is derived from tiny vexpress machine
+having XIP kernel and MMU enabled together.
+
+Signed-off-by: Manish Pandey <manish.pandey2@arm.com>
+Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
+---
+ arch/arm/configs/corstone700_defconfig | 170 +++++++++++++++++++++++++
+ 1 file changed, 170 insertions(+)
+ create mode 100644 arch/arm/configs/corstone700_defconfig
+
+diff --git a/arch/arm/configs/corstone700_defconfig b/arch/arm/configs/corstone700_defconfig
+new file mode 100644
+index 000000000000..d6553a85db16
+--- /dev/null
++++ b/arch/arm/configs/corstone700_defconfig
+@@ -0,0 +1,170 @@
++# CONFIG_LOCALVERSION_AUTO is not set
++# CONFIG_SYSVIPC=y
++# CONFIG_IKCONFIG=y
++# CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=12
++# CONFIG_CGROUPS=y
++# CONFIG_CPUSETS=y
++# CONFIG_UTS_NS is not set
++# CONFIG_IPC_NS is not set
++# CONFIG_PID_NS is not set
++# CONFIG_NET_NS is not set
++CONFIG_BLK_DEV_INITRD=y
++# CONFIG_PROFILING=y
++# CONFIG_OPROFILE=y
++# CONFIG_MODULES=y
++# CONFIG_MODULE_UNLOAD=y
++# CONFIG_LBDAF is not set
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_IOSCHED_DEADLINE is not set
++# CONFIG_IOSCHED_CFQ is not set
++CONFIG_ARCH_TINY_VEXPRESS=y
++CONFIG_ARM_SINGLE_ARMV7A=y
++#CONFIG_DRAM_BASE=0x02100000
++CONFIG_PHYS_OFFSET=0x02100000
++CONFIG_FLASH_MEM_BASE=0x08000000
++CONFIG_FLASH_SIZE=0x4000000
++CONFIG_XIP_KERNEL=y
++CONFIG_XIP_PHYS_ADDR=0x08500000
++# CONFIG_ARCH_VEXPRESS_CA9X4=y
++# CONFIG_ARCH_VEXPRESS_DCSCB=y
++# CONFIG_ARCH_VEXPRESS_TC2_PM=y
++# CONFIG_SWP_EMULATE is not set
++# CONFIG_SMP=y
++CONFIG_HAVE_ARM_ARCH_TIMER=y
++# CONFIG_MCPM=y
++# CONFIG_VMSPLIT_2G=y
++# CONFIG_NR_CPUS=8
++# CONFIG_ARM_PSCI=y
++# CONFIG_AEABI=y
++# CONFIG_CMA=y
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttyAMA0"
++# CONFIG_CPU_IDLE=y
++# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y
++CONFIG_VFP=y
++# CONFIG_NEON=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_NET=y
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++CONFIG_INET=y
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++CONFIG_IP_PNP_BOOTP=y
++# CONFIG_INET_LRO is not set
++# CONFIG_IPV6 is not set
++# CONFIG_WIRELESS is not set
++# CONFIG_NET_9P=y
++# CONFIG_NET_9P_VIRTIO=y
++# CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++CONFIG_DEVTMPFS=y
++# CONFIG_MTD=y
++# CONFIG_MTD_CMDLINE_PARTS=y
++# CONFIG_MTD_BLOCK=y
++# CONFIG_MTD_CFI=y
++# CONFIG_MTD_CFI_INTELEXT=y
++# CONFIG_MTD_CFI_AMDSTD=y
++# CONFIG_MTD_PHYSMAP=y
++# CONFIG_MTD_PHYSMAP_OF=y
++# CONFIG_MTD_PLATRAM=y
++# CONFIG_MTD_UBI=y
++# CONFIG_PROC_DEVICETREE=y
++# CONFIG_VIRTIO_BLK=y
++# CONFIG_SCSI_PROC_FS is not set
++# CONFIG_BLK_DEV_SD=y
++# CONFIG_SCSI_VIRTIO=y
++# CONFIG_ATA=y
++# CONFIG_SATA_PMP is not set
++CONFIG_NETDEVICES=y
++CONFIG_VIRTIO_NET=y
++CONFIG_SMC91X=y
++CONFIG_SMSC911X=y
++# CONFIG_WLAN is not set
++# CONFIG_INPUT_EVDEV=y
++# CONFIG_SERIO_SERPORT is not set
++# CONFIG_SERIO_AMBAKMI=y
++# CONFIG_LEGACY_PTY_COUNT=16
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++# CONFIG_VIRTIO_CONSOLE=y
++# CONFIG_HW_RANDOM=y
++# CONFIG_HW_RANDOM_VIRTIO=y
++# CONFIG_I2C=y
++# CONFIG_I2C_VERSATILE=y
++# CONFIG_SENSORS_VEXPRESS=y
++# CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_VEXPRESS=y
++# CONFIG_FB=y
++# CONFIG_FB_ARMCLCD=y
++# CONFIG_FRAMEBUFFER_CONSOLE=y
++# CONFIG_LOGO=y
++# CONFIG_LOGO_LINUX_MONO is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++# CONFIG_SOUND=y
++# CONFIG_SND=y
++# CONFIG_SND_MIXER_OSS=y
++# CONFIG_SND_PCM_OSS=y
++# CONFIG_SND_DRIVERS is not set
++# CONFIG_SND_ARMAACI=y
++# CONFIG_HID_DRAGONRISE=y
++# CONFIG_HID_GYRATION=y
++# CONFIG_HID_TWINHAN=y
++# CONFIG_HID_NTRIG=y
++# CONFIG_HID_PANTHERLORD=y
++# CONFIG_HID_PETALYNX=y
++# CONFIG_HID_SAMSUNG=y
++# CONFIG_HID_SONY=y
++# CONFIG_HID_SUNPLUS=y
++# CONFIG_HID_GREENASIA=y
++# CONFIG_HID_SMARTJOYPLUS=y
++# CONFIG_HID_TOPSEED=y
++# CONFIG_HID_THRUSTMASTER=y
++# CONFIG_HID_ZEROPLUS=y
++# CONFIG_USB=y
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
++# CONFIG_USB_MON=y
++# CONFIG_USB_STORAGE=y
++# CONFIG_USB_ISP1760=y
++# CONFIG_MMC=y
++# CONFIG_MMC_ARMMMCI=y
++# CONFIG_NEW_LEDS=y
++# CONFIG_LEDS_CLASS=y
++# CONFIG_LEDS_GPIO=y
++# CONFIG_LEDS_TRIGGERS=y
++# CONFIG_LEDS_TRIGGER_HEARTBEAT=y
++# CONFIG_LEDS_TRIGGER_CPU=y
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_DRV_PL031=y
++# CONFIG_VIRTIO_BALLOON=y
++# CONFIG_VIRTIO_MMIO=y
++# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
++# CONFIG_EXT2_FS=y
++# CONFIG_EXT3_FS=y
++# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
++# CONFIG_EXT3_FS_XATTR is not set
++# CONFIG_EXT4_FS=y
++# CONFIG_VFAT_FS=y
++# CONFIG_TMPFS=y
++# CONFIG_JFFS2_FS=y
++# CONFIG_UBIFS_FS=y
++# CONFIG_CRAMFS=y
++# CONFIG_SQUASHFS=y
++# CONFIG_SQUASHFS_LZO=y
++# CONFIG_NFS_FS=y
++# CONFIG_ROOT_NFS=y
++# CONFIG_9P_FS=y
++# CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_ISO8859_1=y
++# CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_FS=y
++# CONFIG_MAGIC_SYSRQ=y
++# CONFIG_DEBUG_KERNEL=y
++# CONFIG_DETECT_HUNG_TASK=y
++# CONFIG_SCHED_DEBUG is not set
++# CONFIG_DEBUG_USER=y
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_HW is not set
++# CONFIG_LTO_MENU=y
++CONFIG_THUMB2_KERNEL=y
+--
+2.17.1
+
new file mode 100644
@@ -0,0 +1,322 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+
+From fb380896ff4e0be235a95ef32b6b3f67a56d1e9b Mon Sep 17 00:00:00 2001
+From: Samarth Parikh <samarthp@ymail.com>
+Date: Sun, 3 Feb 2019 16:35:03 +0000
+Subject: [PATCH 04/20] add driver of mailbox handling unit controller version
+ 2
+
+this driver design is based on MHUv1 driver.
+But there is change of logic while reading device tree
+entry because MHUv2.1 has sender and receiver channels
+separate.
+
+ARM has launched a next version of MHU i.e. MHUv2 with its latest
+subsystems. The main change is that the MHUv2 is now a distributed IP
+with different peripheral views (registers) for the sender and receiver.
+
+Another main difference is that MHUv1 duplex channels are now split into
+simplex/half duplex in MHUv2. MHUv2 has a configurable number of
+communication channels. There is a capability register (MSG_NO_CAP) to
+find out how many channels are available in a system.
+
+The register offsets have also changed for STAT, SET & CLEAR registers
+from 0x0, 0x8 & 0x10 in MHUv1 to 0x0, 0xC & 0x8 in MHUv2 respectively.
+
+0x0 0x4 0x8 0xC 0x1F
+------------------------....-----
+| STAT | | | SET | | |
+------------------------....-----
+ Transmit Channel
+
+0x0 0x4 0x8 0xC 0x1F
+------------------------....-----
+| STAT | | CLR | | | |
+------------------------....-----
+ Receive Channel
+
+The MHU controller can request the receiver to wake-up and once the
+request is removed, the receiver may go back to sleep, but the MHU
+itself does not actively puts a receiver to sleep.
+
+So, in order to wake-up the receiver when the sender wants to send data,
+the sender has to set ACCESS_REQUEST register first in order to wake-up
+receiver, state of which can be detected using ACCESS_READY register.
+ACCESS_REQUEST has an offset of 0xF88 & ACCESS_READY has an offset
+of 0xF8C and are accessible only on any sender channel.
+
+This patch adds necessary changes in a new file required to support the
+latest MHUv2 controller. This patch also need an update in DT binding for
+ARM MHUv2 as we need a second register base (tx base) which would be used
+as the send channel base.
+
+Signed-off-by: Tushar Khandelwal <tushar.khandelwal@arm.com>
+Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
+---
+ drivers/mailbox/Kconfig | 8 ++
+ drivers/mailbox/Makefile | 2 +
+ drivers/mailbox/arm_mhu_v2.c | 219 +++++++++++++++++++++++++++++++++++
+ 3 files changed, 229 insertions(+)
+ create mode 100644 drivers/mailbox/arm_mhu_v2.c
+
+diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
+index ab4eb750bbdd..15d2974d9c20 100644
+--- a/drivers/mailbox/Kconfig
++++ b/drivers/mailbox/Kconfig
+@@ -16,6 +16,14 @@ config ARM_MHU
+ The controller has 3 mailbox channels, the last of which can be
+ used in Secure mode only.
+
++config ARM_MHUv2
++ tristate "ARM MHUv2 Mailbox"
++ depends on ARM_AMBA
++ help
++ Say Y here if you want to build the ARM MHUv2 controller driver.
++ The controller has transmitter and receiver channels with their
++ interrupt lines.
++
+ config IMX_MBOX
+ tristate "i.MX Mailbox"
+ depends on ARCH_MXC || COMPILE_TEST
+diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
+index c22fad6f696b..ba77deeb86a2 100644
+--- a/drivers/mailbox/Makefile
++++ b/drivers/mailbox/Makefile
+@@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST) += mailbox-test.o
+
+ obj-$(CONFIG_ARM_MHU) += arm_mhu.o
+
++obj-$(CONFIG_ARM_MHUv2) += arm_mhu_v2.o
++
+ obj-$(CONFIG_IMX_MBOX) += imx-mailbox.o
+
+ obj-$(CONFIG_ARMADA_37XX_RWTM_MBOX) += armada-37xx-rwtm-mailbox.o
+diff --git a/drivers/mailbox/arm_mhu_v2.c b/drivers/mailbox/arm_mhu_v2.c
+new file mode 100644
+index 000000000000..44ad125bf1c6
+--- /dev/null
++++ b/drivers/mailbox/arm_mhu_v2.c
+@@ -0,0 +1,219 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Message Handling Unit version 2 controller driver
++ * Copyright (C) 2019 ARM Ltd.
++ *
++ * Based on drivers/mailbox/arm_mhu.c
++ *
++ */
++
++#include <linux/interrupt.h>
++#include <linux/mutex.h>
++#include <linux/slab.h>
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/amba/bus.h>
++#include <linux/mailbox_controller.h>
++#include <linux/of_device.h>
++#include <linux/of_address.h>
++
++#define MHU_V2_REG_STAT_OFS 0x0
++#define MHU_V2_REG_CLR_OFS 0x8
++#define MHU_V2_REG_SET_OFS 0xC
++#define MHU_V2_REG_MSG_NO_CAP_OFS 0xF80
++#define MHU_V2_REG_ACC_REQ_OFS 0xF88
++#define MHU_V2_REG_ACC_RDY_OFS 0xF8C
++
++#define MHU_V2_CHANS 2
++
++#define mbox_to_arm_mhuv2(c) container_of(c, struct arm_mhuv2, mbox)
++
++struct mhuv2_link {
++ unsigned int irq;
++ void __iomem *tx_reg;
++ void __iomem *rx_reg;
++};
++
++struct arm_mhuv2 {
++ void __iomem *base;
++ struct mhuv2_link mlink[MHU_V2_CHANS];
++ struct mbox_chan chan[MHU_V2_CHANS];
++ struct mbox_controller mbox;
++};
++
++static irqreturn_t mhuv2_rx_interrupt(int irq, void *p)
++{
++ struct mbox_chan *chan = p;
++ struct mhuv2_link *mlink = chan->con_priv;
++ u32 val;
++
++ val = readl_relaxed(mlink->rx_reg + MHU_V2_REG_STAT_OFS);
++ if (!val)
++ return IRQ_NONE;
++
++ mbox_chan_received_data(chan, (void *)&val);
++
++ writel_relaxed(val, mlink->rx_reg + MHU_V2_REG_CLR_OFS);
++
++ return IRQ_HANDLED;
++}
++
++static bool mhuv2_last_tx_done(struct mbox_chan *chan)
++{
++ struct mhuv2_link *mlink = chan->con_priv;
++ u32 val = readl_relaxed(mlink->tx_reg + MHU_V2_REG_STAT_OFS);
++
++ return (val == 0);
++}
++
++static int mhuv2_send_data(struct mbox_chan *chan, void *data)
++{
++ struct mhuv2_link *mlink = chan->con_priv;
++ u32 *arg = data;
++
++ writel_relaxed(*arg, mlink->tx_reg + MHU_V2_REG_SET_OFS);
++
++ return 0;
++}
++
++static int mhuv2_startup(struct mbox_chan *chan)
++{
++ struct mhuv2_link *mlink = chan->con_priv;
++ u32 val;
++ int ret;
++ struct arm_mhuv2 *mhuv2 = mbox_to_arm_mhuv2(chan->mbox);
++
++ writel_relaxed(0x1, mhuv2->base + MHU_V2_REG_ACC_REQ_OFS);
++
++ val = readl_relaxed(mlink->tx_reg + MHU_V2_REG_STAT_OFS);
++ writel_relaxed(val, mlink->tx_reg + MHU_V2_REG_CLR_OFS);
++
++ ret = request_irq(mlink->irq, mhuv2_rx_interrupt,
++ IRQF_SHARED, "mhuv2_link", chan);
++ if (ret) {
++ dev_err(chan->mbox->dev,
++ "unable to acquire IRQ %d\n", mlink->irq);
++ return ret;
++ }
++
++ return 0;
++}
++
++static void mhuv2_shutdown(struct mbox_chan *chan)
++{
++ struct mhuv2_link *mlink = chan->con_priv;
++ struct arm_mhuv2 *mhuv2 = mbox_to_arm_mhuv2(chan->mbox);
++
++ writel_relaxed(0x0, mhuv2->base + MHU_V2_REG_ACC_REQ_OFS);
++
++ free_irq(mlink->irq, chan);
++}
++
++static const struct mbox_chan_ops mhuv2_ops = {
++ .send_data = mhuv2_send_data,
++ .startup = mhuv2_startup,
++ .shutdown = mhuv2_shutdown,
++ .last_tx_done = mhuv2_last_tx_done,
++};
++
++static int mhuv2_probe(struct amba_device *adev, const struct amba_id *id)
++{
++ int i, err;
++ struct arm_mhuv2 *mhuv2;
++ struct device *dev = &adev->dev;
++ void __iomem *rx_base, *tx_base;
++ const struct device_node *np = dev->of_node;
++ unsigned int pchans;
++
++ /* Allocate memory for device */
++ mhuv2 = devm_kzalloc(dev, sizeof(*mhuv2), GFP_KERNEL);
++ if (!mhuv2)
++ return -ENOMEM;
++
++ tx_base = of_iomap((struct device_node *)np, 0);
++ if (!tx_base) {
++ dev_err(dev, "failed to map tx registers\n");
++ iounmap(rx_base);
++ return -ENOMEM;
++ }
++
++ rx_base = of_iomap((struct device_node *)np, 1);
++ if (!rx_base) {
++ dev_err(dev, "failed to map rx registers\n");
++ return -ENOMEM;
++ }
++
++
++ pchans = readl_relaxed(tx_base + MHU_V2_REG_MSG_NO_CAP_OFS);
++ if (pchans == 0 || pchans > MHU_V2_CHANS || pchans % 2) {
++ dev_err(dev, "invalid number of channels %d\n", pchans);
++ iounmap(rx_base);
++ iounmap(tx_base);
++ return -EINVAL;
++ }
++ for (i = 0; i < pchans/2; i++) {
++ mhuv2->chan[i].con_priv = &mhuv2->mlink[i];
++ mhuv2->mlink[i].irq = adev->irq[i];
++ mhuv2->mlink[i].rx_reg = rx_base + i*0x4;
++ mhuv2->mlink[i].tx_reg = tx_base + i*0x4;
++ }
++
++ mhuv2->base = tx_base;
++ mhuv2->mbox.dev = dev;
++ mhuv2->mbox.chans = &mhuv2->chan[0];
++ mhuv2->mbox.num_chans = pchans;
++ mhuv2->mbox.ops = &mhuv2_ops;
++ mhuv2->mbox.txdone_irq = false;
++ mhuv2->mbox.txdone_poll = true;
++ mhuv2->mbox.txpoll_period = 1;
++
++ amba_set_drvdata(adev, mhuv2);
++
++ err = mbox_controller_register(&mhuv2->mbox);
++ if (err) {
++ dev_err(dev, "failed to register mailboxes %d\n", err);
++ iounmap(rx_base);
++ iounmap(tx_base);
++ return err;
++ }
++
++ dev_info(dev, "ARM MHUv2 Mailbox driver registered\n");
++ return 0;
++}
++
++static int mhuv2_remove(struct amba_device *adev)
++{
++ struct arm_mhuv2 *mhuv2 = amba_get_drvdata(adev);
++
++ mbox_controller_unregister(&mhuv2->mbox);
++
++ return 0;
++}
++
++static struct amba_id mhuv2_ids[] = {
++ {
++ .id = 0x4b0d1,
++ .mask = 0xfffff,
++ },
++ {
++ .id = 0xbb0d1,
++ .mask = 0xfffff,
++ },
++ { 0, 0 },
++};
++MODULE_DEVICE_TABLE(amba, mhuv2_ids);
++
++static struct amba_driver arm_mhuv2_driver = {
++ .drv = {
++ .name = "mhuv2",
++ },
++ .id_table = mhuv2_ids,
++ .probe = mhuv2_probe,
++ .remove = mhuv2_remove,
++};
++module_amba_driver(arm_mhuv2_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("ARM MHUv2 Driver");
++MODULE_AUTHOR("Samarth Parikh <samarthp@ymail.com>");
+--
+2.17.1
+
new file mode 100644
@@ -0,0 +1,202 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+
+From f864a1bcd09b2f2cbe0c0b923d6d974d16b602ed Mon Sep 17 00:00:00 2001
+From: Tushar Khandelwal <tushar.khandelwal@arm.com>
+Date: Sun, 3 Feb 2019 16:41:14 +0000
+Subject: [PATCH 05/20] add rpmsg based on rpmsg char driver using mailbox
+
+this driver registers a rpmsg client which inturn registers a mailbox
+client to commmunicate the remote processor over MHU
+
+Signed-off-by: Tushar Khandelwal <tushar.khandelwal@arm.com>
+Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
+---
+ drivers/rpmsg/Kconfig | 10 +++
+ drivers/rpmsg/Makefile | 1 +
+ drivers/rpmsg/rpmsg_arm_mailbox.c | 141 ++++++++++++++++++++++++++++++
+ 3 files changed, 152 insertions(+)
+ create mode 100644 drivers/rpmsg/rpmsg_arm_mailbox.c
+
+diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
+index a9108ff563dc..13f04012caeb 100644
+--- a/drivers/rpmsg/Kconfig
++++ b/drivers/rpmsg/Kconfig
+@@ -6,6 +6,16 @@ menu "Rpmsg drivers"
+ config RPMSG
+ tristate
+
++config RPMSG_ARM
++ tristate "ARM RPMSG driver"
++ select RPMSG
++ depends on HAS_IOMEM
++ depends on MAILBOX
++ help
++ Say y here to enable support for rpmsg lient driver which is built
++ around mailbox client using Arm MHUv2.1 as physical medium.This
++ driver enables communication which remote processor using MHU.
++
+ config RPMSG_CHAR
+ tristate "RPMSG device interface"
+ depends on RPMSG
+diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
+index ae92a7fb08f6..3f0238a66a00 100644
+--- a/drivers/rpmsg/Makefile
++++ b/drivers/rpmsg/Makefile
+@@ -1,5 +1,6 @@
+ # SPDX-License-Identifier: GPL-2.0
+ obj-$(CONFIG_RPMSG) += rpmsg_core.o
++obj-$(CONFIG_RPMSG_ARM) += rpmsg_arm_mailbox.o
+ obj-$(CONFIG_RPMSG_CHAR) += rpmsg_char.o
+ obj-$(CONFIG_RPMSG_MTK_SCP) += mtk_rpmsg.o
+ obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o
+diff --git a/drivers/rpmsg/rpmsg_arm_mailbox.c b/drivers/rpmsg/rpmsg_arm_mailbox.c
+new file mode 100644
+index 000000000000..af6c47737d06
+--- /dev/null
++++ b/drivers/rpmsg/rpmsg_arm_mailbox.c
+@@ -0,0 +1,141 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * rpmsg client driver using mailbox client interface
++ *
++ * Copyright (C) 2019 ARM Ltd.
++ *
++ */
++
++#include <linux/bitmap.h>
++#include <linux/export.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/ktime.h>
++#include <linux/mailbox_client.h>
++#include <linux/module.h>
++#include <linux/of_address.h>
++#include <linux/of_device.h>
++#include <linux/processor.h>
++#include <linux/semaphore.h>
++#include <linux/slab.h>
++#include <linux/rpmsg.h>
++#include "rpmsg_internal.h"
++
++#define RPMSG_NAME "arm_rpmsg"
++#define RPMSG_ADDR_ANY 0xFFFFFFFF
++#define TX_TIMEOUT 500 /*by half second*/
++
++struct rpmsg_endpoint *eptg;
++
++static void message_from_se(struct mbox_client *cl, void *mssg)
++{
++ eptg->cb(eptg->rpdev, mssg, 4, eptg->priv, RPMSG_ADDR_ANY);
++}
++
++
++static void arm_destroy_ept(struct rpmsg_endpoint *ept)
++{
++ kfree(ept);
++}
++
++static int arm_send(struct rpmsg_endpoint *ept, void *data, int len)
++{
++ struct mbox_client *cl;
++ struct mbox_chan *mbox;
++
++ cl = kzalloc(sizeof(struct mbox_client), GFP_KERNEL);
++ cl->dev = ept->rpdev->dev.parent;
++ cl->rx_callback = message_from_se;
++ cl->tx_done = NULL; /* operate in blocking mode */
++ cl->tx_block = true;
++ cl->tx_tout = TX_TIMEOUT; /* by half a second */
++ cl->knows_txdone = false; /* depending upon protocol */
++
++ mbox = mbox_request_channel(cl, 0);
++ if (mbox == NULL) {
++ dev_printk(KERN_ERR, cl->dev, "\nCannot get the channel\n");
++ return -1;
++ }
++ mbox_send_message(mbox, data);
++ mbox_free_channel(mbox);
++ return 0;
++}
++
++static const struct rpmsg_endpoint_ops arm_endpoint_ops = {
++ .destroy_ept = arm_destroy_ept,
++ .send = arm_send,
++};
++
++
++static struct rpmsg_endpoint *arm_create_ept(struct rpmsg_device *rpdev,
++ rpmsg_rx_cb_t cb, void *priv, struct rpmsg_channel_info chinfo)
++{
++ struct rpmsg_endpoint *ept;
++
++ ept = kzalloc(sizeof(*ept), GFP_KERNEL);
++ if (!ept)
++ return NULL;
++
++ kref_init(&ept->refcount);
++ ept->rpdev = rpdev;
++ ept->cb = cb;
++ ept->priv = priv;
++ ept->ops = &arm_endpoint_ops;
++ eptg = ept;
++
++ return ept;
++}
++
++static const struct rpmsg_device_ops arm_device_ops = {
++ .create_ept = arm_create_ept,
++};
++
++
++static void arm_release_device(struct device *dev)
++{
++ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
++
++ kfree(rpdev);
++}
++
++
++static int client_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct rpmsg_device *rpdev;
++
++ rpdev = kzalloc(sizeof(*rpdev), GFP_KERNEL);
++ if (!rpdev)
++ return -ENOMEM;
++
++ /* Assign callbacks for rpmsg_device */
++ rpdev->ops = &arm_device_ops;
++
++ /* Assign public information to the rpmsg_device */
++ strncpy(rpdev->id.name, RPMSG_NAME, strlen(RPMSG_NAME));
++
++ rpdev->dev.parent = dev;
++ rpdev->dev.release = arm_release_device;
++
++ return rpmsg_chrdev_register_device(rpdev);
++}
++
++static const struct of_device_id client_of_match[] = {
++ { .compatible = "arm,client", .data = NULL },
++ { /* Sentinel */ },
++};
++
++static struct platform_driver client_driver = {
++ .driver = {
++ .name = "arm-mhu-client",
++ .of_match_table = client_of_match,
++ },
++ .probe = client_probe,
++};
++
++module_platform_driver(client_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("ARM RPMSG Driver");
++MODULE_AUTHOR("Tushar Khandelwal <tushar.khandelwal@arm.com>");
++
+--
+2.17.1
+
new file mode 100644
@@ -0,0 +1,30 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+
+From 83f137956333e57b7313cb5c344df0eb52caefdf Mon Sep 17 00:00:00 2001
+From: Tushar Khandelwal <tushar.khandelwal@arm.com>
+Date: Thu, 2 May 2019 23:23:11 +0100
+Subject: [PATCH 06/20] enable arm MHU driver and RPMSG char driver
+
+Signed-off-by: Tushar Khandelwal <tushar.khandelwal@arm.com>
+Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
+---
+ arch/arm/configs/corstone700_defconfig | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/arch/arm/configs/corstone700_defconfig b/arch/arm/configs/corstone700_defconfig
+index d6553a85db16..5d5244ce8278 100644
+--- a/arch/arm/configs/corstone700_defconfig
++++ b/arch/arm/configs/corstone700_defconfig
+@@ -168,3 +168,8 @@ CONFIG_RTC_DRV_PL031=y
+ # CONFIG_CRYPTO_HW is not set
+ # CONFIG_LTO_MENU=y
+ CONFIG_THUMB2_KERNEL=y
++CONFIG_MAILBOX=y
++CONFIG_ARM_MHUv2=y
++CONFIG_RPMSG=y
++CONFIG_RPMSG_CHAR=y
++CONFIG_RPMSG_ARM=y
+--
+2.17.1
+
new file mode 100644
@@ -0,0 +1,148 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+
+From ae9eb0666ea462bf742abc8effc3cb3ec145cbae Mon Sep 17 00:00:00 2001
+From: Morten Borup Petersen <morten.petersen@arm.com>
+Date: Fri, 3 May 2019 10:45:20 +0100
+Subject: [PATCH 07/20] allow creation of multiple arm rpmsg channels
+
+This commit introduces support for accessing multiple channels
+through the arm rpmsg driver.
+To do this, information connecting rpmsg endpoints, mailbox channels
+and mailbox names are stored for each created endpoint.
+rpmsg endpoints and now to be created by referring to mailbox
+names defined in the device-tree.
+
+Signed-off-by: Morten Borup Petersen <morten.petersen@arm.com>
+Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
+---
+ drivers/rpmsg/rpmsg_arm_mailbox.c | 69 +++++++++++++++++++++++++++----
+ 1 file changed, 60 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/rpmsg/rpmsg_arm_mailbox.c b/drivers/rpmsg/rpmsg_arm_mailbox.c
+index af6c47737d06..1cf7e20142e2 100644
+--- a/drivers/rpmsg/rpmsg_arm_mailbox.c
++++ b/drivers/rpmsg/rpmsg_arm_mailbox.c
+@@ -25,35 +25,80 @@
+ #define RPMSG_ADDR_ANY 0xFFFFFFFF
+ #define TX_TIMEOUT 500 /*by half second*/
+
+-struct rpmsg_endpoint *eptg;
++struct arm_ept_info {
++ struct rpmsg_channel_info info;
++ struct rpmsg_endpoint *ept;
++ struct mbox_client *cl;
++
++ struct list_head node;
++};
+
+-static void message_from_se(struct mbox_client *cl, void *mssg)
++static LIST_HEAD(arm_ept_infos);
++
++static void arm_msg_rx_handler(struct mbox_client *cl, void *mssg)
+ {
+- eptg->cb(eptg->rpdev, mssg, 4, eptg->priv, RPMSG_ADDR_ANY);
++ struct arm_ept_info *it = NULL;
++
++ list_for_each_entry(it, &arm_ept_infos, node) {
++ if (it->cl == cl) {
++ struct rpmsg_endpoint *ept = it->ept;
++
++ ept->cb(ept->rpdev, mssg, 4, ept->priv, RPMSG_ADDR_ANY);
++ return;
++ }
++ }
+ }
+
+
+ static void arm_destroy_ept(struct rpmsg_endpoint *ept)
+ {
++ struct arm_ept_info *it = NULL;
++
++ list_for_each_entry(it, &arm_ept_infos, node) {
++ if (it->ept == ept) {
++ list_del(&it->node);
++ kfree(it);
++ break;
++ }
++ }
+ kfree(ept);
+ }
+
+ static int arm_send(struct rpmsg_endpoint *ept, void *data, int len)
+ {
++ struct arm_ept_info *it = NULL;
++ struct arm_ept_info *arm_ept = NULL;
+ struct mbox_client *cl;
+ struct mbox_chan *mbox;
+
++ // Locate registered endpoint
++ list_for_each_entry(it, &arm_ept_infos, node) {
++ if (it->ept == ept) {
++ arm_ept = it;
++ break;
++ }
++ }
++
++ if (arm_ept == NULL) {
++ dev_printk(KERN_ERR, cl->dev,
++ "RPMsg ARM: Invalid endpoint\n");
++ return -1;
++ }
++
+ cl = kzalloc(sizeof(struct mbox_client), GFP_KERNEL);
+ cl->dev = ept->rpdev->dev.parent;
+- cl->rx_callback = message_from_se;
++ cl->rx_callback = arm_msg_rx_handler;
+ cl->tx_done = NULL; /* operate in blocking mode */
+ cl->tx_block = true;
+ cl->tx_tout = TX_TIMEOUT; /* by half a second */
+ cl->knows_txdone = false; /* depending upon protocol */
++ arm_ept->cl = cl;
+
+- mbox = mbox_request_channel(cl, 0);
+- if (mbox == NULL) {
+- dev_printk(KERN_ERR, cl->dev, "\nCannot get the channel\n");
++ mbox = mbox_request_channel_byname(cl, arm_ept->info.name);
++ if (IS_ERR_OR_NULL(mbox)) {
++ dev_printk(KERN_ERR, cl->dev,
++ "RPMsg ARM: Cannot get channel by name: '%s'\n",
++ arm_ept->info.name);
+ return -1;
+ }
+ mbox_send_message(mbox, data);
+@@ -71,6 +116,7 @@ static struct rpmsg_endpoint *arm_create_ept(struct rpmsg_device *rpdev,
+ rpmsg_rx_cb_t cb, void *priv, struct rpmsg_channel_info chinfo)
+ {
+ struct rpmsg_endpoint *ept;
++ struct arm_ept_info *ept_mbox;
+
+ ept = kzalloc(sizeof(*ept), GFP_KERNEL);
+ if (!ept)
+@@ -81,8 +127,13 @@ static struct rpmsg_endpoint *arm_create_ept(struct rpmsg_device *rpdev,
+ ept->cb = cb;
+ ept->priv = priv;
+ ept->ops = &arm_endpoint_ops;
+- eptg = ept;
+
++ // store chinfo for determining destination mailbox when sending
++ ept_mbox = kzalloc(sizeof(*ept_mbox), GFP_KERNEL);
++ ept_mbox->info = chinfo;
++ strncpy(ept_mbox->info.name, chinfo.name, RPMSG_NAME_SIZE);
++ ept_mbox->ept = ept;
++ list_add(&ept_mbox->node, &arm_ept_infos);
+ return ept;
+ }
+
+@@ -112,7 +163,7 @@ static int client_probe(struct platform_device *pdev)
+ rpdev->ops = &arm_device_ops;
+
+ /* Assign public information to the rpmsg_device */
+- strncpy(rpdev->id.name, RPMSG_NAME, strlen(RPMSG_NAME));
++ memcpy(rpdev->id.name, RPMSG_NAME, strlen(RPMSG_NAME));
+
+ rpdev->dev.parent = dev;
+ rpdev->dev.release = arm_release_device;
+--
+2.17.1
+
new file mode 100644
@@ -0,0 +1,59 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+
+From 5ec2338142acb7c1ca191fc79f9ea3ecc96dc125 Mon Sep 17 00:00:00 2001
+From: Morten Borup Petersen <morten.petersen@arm.com>
+Date: Tue, 25 Jun 2019 13:23:51 +0100
+Subject: [PATCH 08/20] mailbox: enable combined receiver interrupt when using
+ MHUv2.1
+
+Signed-off-by: Morten Borup Petersen <morten.petersen@arm.com>
+Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
+---
+ drivers/mailbox/arm_mhu_v2.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+diff --git a/drivers/mailbox/arm_mhu_v2.c b/drivers/mailbox/arm_mhu_v2.c
+index 44ad125bf1c6..7780958a16ab 100644
+--- a/drivers/mailbox/arm_mhu_v2.c
++++ b/drivers/mailbox/arm_mhu_v2.c
+@@ -24,6 +24,11 @@
+ #define MHU_V2_REG_MSG_NO_CAP_OFS 0xF80
+ #define MHU_V2_REG_ACC_REQ_OFS 0xF88
+ #define MHU_V2_REG_ACC_RDY_OFS 0xF8C
++#define MHU_V2_INT_EN_OFS 0xF98
++#define MHU_V2_AIDR_OFS 0xFCC
++
++#define MHU_V2_CHCOMB BIT(2)
++#define MHU_V2_AIDR_MINOR(_reg) ((_reg) & 0xF)
+
+ #define MHU_V2_CHANS 2
+
+@@ -117,6 +122,16 @@ static const struct mbox_chan_ops mhuv2_ops = {
+ .last_tx_done = mhuv2_last_tx_done,
+ };
+
++void mhuv2_check_enable_cmbint(struct mhuv2_link *link)
++{
++ const u32 aidr = readl_relaxed(link->rx_reg + MHU_V2_AIDR_OFS);
++
++ if (MHU_V2_AIDR_MINOR(aidr) == 1) {
++ // Enable combined receiver interrupt for MHUv2.1
++ writel_relaxed(MHU_V2_CHCOMB, link->rx_reg + MHU_V2_INT_EN_OFS);
++ }
++}
++
+ static int mhuv2_probe(struct amba_device *adev, const struct amba_id *id)
+ {
+ int i, err;
+@@ -157,6 +172,7 @@ static int mhuv2_probe(struct amba_device *adev, const struct amba_id *id)
+ mhuv2->mlink[i].irq = adev->irq[i];
+ mhuv2->mlink[i].rx_reg = rx_base + i*0x4;
+ mhuv2->mlink[i].tx_reg = tx_base + i*0x4;
++ mhuv2_check_enable_cmbint(&mhuv2->mlink[i]);
+ }
+
+ mhuv2->base = tx_base;
+--
+2.17.1
+
new file mode 100644
@@ -0,0 +1,232 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+
+From dc2c23ba5acf17644af5ce5efc90667ce5da56c6 Mon Sep 17 00:00:00 2001
+From: Morten Borup Petersen <Morten.Petersen@arm.com>
+Date: Fri, 1 Mar 2019 13:29:18 +0000
+Subject: [PATCH 09/20] misc: arm: add corstone700 external system harness
+ driver
+
+This commit adds a driver and device node for controlling the external
+system harness of arm corstone700.
+Currently, the only functionality is ioctl command: 0x0, which will
+deassert the CPU_WAIT pin of the external system harness attached to the
+driver.
+
+Signed-off-by: Morten Borup Petersen <Morten.Petersen@arm.com>
+Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
+---
+ arch/arm/configs/corstone700_defconfig | 1 +
+ drivers/misc/Kconfig | 1 +
+ drivers/misc/Makefile | 1 +
+ drivers/misc/arm/Kconfig | 5 +
+ drivers/misc/arm/Makefile | 1 +
+ drivers/misc/arm/extsys_ctrl.c | 147 +++++++++++++++++++++++++
+ 6 files changed, 156 insertions(+)
+ create mode 100644 drivers/misc/arm/Kconfig
+ create mode 100644 drivers/misc/arm/Makefile
+ create mode 100644 drivers/misc/arm/extsys_ctrl.c
+
+diff --git a/arch/arm/configs/corstone700_defconfig b/arch/arm/configs/corstone700_defconfig
+index 5d5244ce8278..629b2163a534 100644
+--- a/arch/arm/configs/corstone700_defconfig
++++ b/arch/arm/configs/corstone700_defconfig
+@@ -173,3 +173,4 @@ CONFIG_ARM_MHUv2=y
+ CONFIG_RPMSG=y
+ CONFIG_RPMSG_CHAR=y
+ CONFIG_RPMSG_ARM=y
++CONFIG_EXTSYS_CTRL=y
+\ No newline at end of file
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index 7f0d48f406e3..8d904cd46e4b 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -480,4 +480,5 @@ source "drivers/misc/cxl/Kconfig"
+ source "drivers/misc/ocxl/Kconfig"
+ source "drivers/misc/cardreader/Kconfig"
+ source "drivers/misc/habanalabs/Kconfig"
++source "drivers/misc/arm/Kconfig"
+ endmenu
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index c1860d35dc7e..9eec96cfb750 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -57,3 +57,4 @@ obj-y += cardreader/
+ obj-$(CONFIG_PVPANIC) += pvpanic.o
+ obj-$(CONFIG_HABANA_AI) += habanalabs/
+ obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o
++obj-y += arm/
+diff --git a/drivers/misc/arm/Kconfig b/drivers/misc/arm/Kconfig
+new file mode 100644
+index 000000000000..a808b5b17b8d
+--- /dev/null
++++ b/drivers/misc/arm/Kconfig
+@@ -0,0 +1,5 @@
++config EXTSYS_CTRL
++ tristate "Arm External System control driver"
++ help
++ Say y here to enable support for external system control
++ driver for the Arm Corstone-700 platform
+diff --git a/drivers/misc/arm/Makefile b/drivers/misc/arm/Makefile
+new file mode 100644
+index 000000000000..1ca3084cf8a0
+--- /dev/null
++++ b/drivers/misc/arm/Makefile
+@@ -0,0 +1 @@
++obj-$(CONFIG_EXTSYS_CTRL) += extsys_ctrl.o
+diff --git a/drivers/misc/arm/extsys_ctrl.c b/drivers/misc/arm/extsys_ctrl.c
+new file mode 100644
+index 000000000000..1ff384ef9c0d
+--- /dev/null
++++ b/drivers/misc/arm/extsys_ctrl.c
+@@ -0,0 +1,147 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Arm Corstone700 external system reset control driver
++ *
++ * Copyright (C) 2019 Arm Ltd.
++ *
++ */
++
++#include <linux/fs.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/mod_devicetable.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/miscdevice.h>
++#include <linux/init.h>
++
++#define EXTSYS_DRV_NAME "extsys_ctrl"
++#define EXTSYS_MAX_DEVS 4
++
++#define EXTSYS_RST_SIZE U(0x8)
++#define EXTSYS_RST_CTRL_OFF U(0x0)
++#define EXTSYS_RST_ST_OFF U(0x4)
++
++/* External system reset control indexes */
++#define EXTSYS_CPU_WAIT (0x0)
++#define EXTSYS_RST_REQ (0x1)
++
++/* External system reset status masks */
++#define EXTSYS_RST_ST_ACK_OFF U(0x1)
++
++/* No Reset Requested */
++#define EXTSYS_RST_ST_ACK_NRR (0x0 << EXTSYS_RST_ST_ACK_OFF)
++
++/* Reset Request Complete */
++#define EXTSYS_RST_ST_ACK_RRC (0x2 << EXTSYS_RST_ST_ACK_OFF)
++
++/* Reset Request Unable to Complete */
++#define EXTSYS_RST_ST_ACK_RRUC (0x3 << EXTSYS_RST_ST_ACK_OFF)
++
++/* IOCTL commands */
++#define EXTSYS_CPU_WAIT_DISABLE 0x0
++
++struct extsys_ctrl {
++ struct miscdevice miscdev;
++ void __iomem *reset_reg;
++ void __iomem *set_reg;
++};
++
++#define CLEAR_BIT(addr, index) writel(readl(addr) & ~(1UL << index), addr)
++
++static long extsys_ctrl_ioctl(struct file *f, unsigned int cmd,
++ unsigned long arg)
++{
++ struct extsys_ctrl *extsys;
++
++ extsys = container_of(f->private_data, struct extsys_ctrl, miscdev);
++
++ switch (cmd) {
++ case EXTSYS_CPU_WAIT_DISABLE:
++ CLEAR_BIT(extsys->reset_reg, EXTSYS_CPU_WAIT);
++ break;
++
++ default:
++ break;
++ }
++
++ return 0;
++}
++
++static const struct file_operations extsys_ctrl_fops = {
++ .owner = THIS_MODULE,
++ .unlocked_ioctl = extsys_ctrl_ioctl,
++};
++
++static int extsys_ctrl_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct extsys_ctrl *extsys;
++ struct resource *res;
++ void __iomem *reset_reg;
++ void __iomem *set_reg;
++ int ret;
++
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rstreg");
++ reset_reg = devm_ioremap_resource(dev, res);
++ if (IS_ERR(reset_reg))
++ return PTR_ERR(reset_reg);
++
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "streg");
++ set_reg = devm_ioremap_resource(dev, res);
++ if (IS_ERR(set_reg))
++ return PTR_ERR(set_reg);
++
++ extsys = devm_kzalloc(dev, sizeof(*extsys), GFP_KERNEL);
++ if (!extsys)
++ return -ENOMEM;
++
++ extsys->reset_reg = reset_reg;
++ extsys->set_reg = set_reg;
++
++ extsys->miscdev.minor = MISC_DYNAMIC_MINOR;
++ extsys->miscdev.name = EXTSYS_DRV_NAME;
++ extsys->miscdev.fops = &extsys_ctrl_fops;
++ extsys->miscdev.parent = dev;
++
++ ret = misc_register(&extsys->miscdev);
++ if (ret)
++ return ret;
++
++ dev_info(dev, "external system controller ready\n");
++
++ return 0;
++}
++
++static int extsys_ctrl_remove(struct platform_device *pdev)
++{
++ struct extsys_ctrl *extsys = dev_get_drvdata(&pdev->dev);
++
++ misc_deregister(&extsys->miscdev);
++
++ return 0;
++}
++
++static const struct of_device_id extsys_ctrl_match[] = {
++ { .compatible = "arm,extsys_ctrl" },
++ { },
++};
++MODULE_DEVICE_TABLE(of, extsys_ctrl_match);
++
++static struct platform_driver extsys_ctrl_driver = {
++ .driver = {
++ .name = EXTSYS_DRV_NAME,
++ .of_match_table = extsys_ctrl_match,
++ },
++ .probe = extsys_ctrl_probe,
++ .remove = extsys_ctrl_remove,
++};
++module_platform_driver(extsys_ctrl_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("Arm External System Control Driver");
++MODULE_AUTHOR("Morten Borup Petersen <morten.petersen@arm.com>");
++MODULE_AUTHOR("Rui Miguel Silva <rui.silva@linaro.org>");
+--
+2.17.1
+
new file mode 100644
@@ -0,0 +1,181 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+
+From a0cee835763d884d8ce44d01d5271e7f2e68313f Mon Sep 17 00:00:00 2001
+From: Morten Borup Petersen <morten.petersen@arm.com>
+Date: Thu, 30 May 2019 15:30:54 +0100
+Subject: [PATCH 10/20] arm: containerize endpoint and mailbox information
+
+This commit adds the rpmsg_endpoint and mbox_client structs as members of the
+arm_channel struct. This allows for usage of the container_of macro, vastly
+simplifying lookup between endpoints and mailboxes.
+
+Furthermore, a memory leak from the allocation of mbox_client's is fixed.
+
+Signed-off-by: Morten Borup Petersen <morten.petersen@arm.com>
+Signed-off-by: Tushar Khandelwal <tushar.khandelwal@arm.com>
+Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
+---
+ drivers/rpmsg/rpmsg_arm_mailbox.c | 113 ++++++++++--------------------
+ 1 file changed, 36 insertions(+), 77 deletions(-)
+
+diff --git a/drivers/rpmsg/rpmsg_arm_mailbox.c b/drivers/rpmsg/rpmsg_arm_mailbox.c
+index 1cf7e20142e2..4933187c61ea 100644
+--- a/drivers/rpmsg/rpmsg_arm_mailbox.c
++++ b/drivers/rpmsg/rpmsg_arm_mailbox.c
+@@ -23,84 +23,41 @@
+
+ #define RPMSG_NAME "arm_rpmsg"
+ #define RPMSG_ADDR_ANY 0xFFFFFFFF
+-#define TX_TIMEOUT 500 /*by half second*/
+
+-struct arm_ept_info {
+- struct rpmsg_channel_info info;
+- struct rpmsg_endpoint *ept;
+- struct mbox_client *cl;
+-
+- struct list_head node;
++struct arm_channel {
++ struct rpmsg_channel_info chinfo;
++ struct rpmsg_endpoint ept;
++ struct mbox_client cl;
+ };
+
+-static LIST_HEAD(arm_ept_infos);
++#define arm_channel_from_rpmsg(_ept) container_of(_ept, struct arm_channel, ept)
++#define arm_channel_from_mbox(_ept) container_of(_ept, struct arm_channel, cl)
++
+
+ static void arm_msg_rx_handler(struct mbox_client *cl, void *mssg)
+ {
+- struct arm_ept_info *it = NULL;
+-
+- list_for_each_entry(it, &arm_ept_infos, node) {
+- if (it->cl == cl) {
+- struct rpmsg_endpoint *ept = it->ept;
+-
+- ept->cb(ept->rpdev, mssg, 4, ept->priv, RPMSG_ADDR_ANY);
+- return;
+- }
+- }
++ struct arm_channel* channel = arm_channel_from_mbox(cl);
++ channel->ept.cb(channel->ept.rpdev, mssg, 4, channel->ept.priv, RPMSG_ADDR_ANY);
+ }
+
+
+ static void arm_destroy_ept(struct rpmsg_endpoint *ept)
+ {
+- struct arm_ept_info *it = NULL;
+-
+- list_for_each_entry(it, &arm_ept_infos, node) {
+- if (it->ept == ept) {
+- list_del(&it->node);
+- kfree(it);
+- break;
+- }
+- }
+- kfree(ept);
++ struct arm_channel *channel = arm_channel_from_rpmsg(ept);
++ kfree(channel);
+ }
+
+ static int arm_send(struct rpmsg_endpoint *ept, void *data, int len)
+ {
+- struct arm_ept_info *it = NULL;
+- struct arm_ept_info *arm_ept = NULL;
+- struct mbox_client *cl;
++ struct arm_channel *channel = arm_channel_from_rpmsg(ept);
+ struct mbox_chan *mbox;
+
+- // Locate registered endpoint
+- list_for_each_entry(it, &arm_ept_infos, node) {
+- if (it->ept == ept) {
+- arm_ept = it;
+- break;
+- }
+- }
+-
+- if (arm_ept == NULL) {
+- dev_printk(KERN_ERR, cl->dev,
+- "RPMsg ARM: Invalid endpoint\n");
+- return -1;
+- }
+-
+- cl = kzalloc(sizeof(struct mbox_client), GFP_KERNEL);
+- cl->dev = ept->rpdev->dev.parent;
+- cl->rx_callback = arm_msg_rx_handler;
+- cl->tx_done = NULL; /* operate in blocking mode */
+- cl->tx_block = true;
+- cl->tx_tout = TX_TIMEOUT; /* by half a second */
+- cl->knows_txdone = false; /* depending upon protocol */
+- arm_ept->cl = cl;
+-
+- mbox = mbox_request_channel_byname(cl, arm_ept->info.name);
++ mbox = mbox_request_channel_byname(&channel->cl, channel->chinfo.name);
+ if (IS_ERR_OR_NULL(mbox)) {
+- dev_printk(KERN_ERR, cl->dev,
+- "RPMsg ARM: Cannot get channel by name: '%s'\n",
+- arm_ept->info.name);
++ printk("RPMsg ARM: Cannot get channel by name: '%s'\n", channel->chinfo.name);
+ return -1;
+ }
++
+ mbox_send_message(mbox, data);
+ mbox_free_channel(mbox);
+ return 0;
+@@ -115,26 +72,29 @@ static const struct rpmsg_endpoint_ops arm_endpoint_ops = {
+ static struct rpmsg_endpoint *arm_create_ept(struct rpmsg_device *rpdev,
+ rpmsg_rx_cb_t cb, void *priv, struct rpmsg_channel_info chinfo)
+ {
+- struct rpmsg_endpoint *ept;
+- struct arm_ept_info *ept_mbox;
+-
+- ept = kzalloc(sizeof(*ept), GFP_KERNEL);
+- if (!ept)
+- return NULL;
+-
+- kref_init(&ept->refcount);
+- ept->rpdev = rpdev;
+- ept->cb = cb;
+- ept->priv = priv;
+- ept->ops = &arm_endpoint_ops;
++ struct arm_channel* channel;
++ channel = kzalloc(sizeof(*channel), GFP_KERNEL);
+
+ // store chinfo for determining destination mailbox when sending
+- ept_mbox = kzalloc(sizeof(*ept_mbox), GFP_KERNEL);
+- ept_mbox->info = chinfo;
+- strncpy(ept_mbox->info.name, chinfo.name, RPMSG_NAME_SIZE);
+- ept_mbox->ept = ept;
+- list_add(&ept_mbox->node, &arm_ept_infos);
+- return ept;
++ channel->chinfo = chinfo;
++ strncpy(channel->chinfo.name, chinfo.name, RPMSG_NAME_SIZE);
++
++ // Initialize rpmsg endpoint
++ kref_init(&channel->ept.refcount);
++ channel->ept.rpdev = rpdev;
++ channel->ept.cb = cb;
++ channel->ept.priv = priv;
++ channel->ept.ops = &arm_endpoint_ops;
++
++ // Initialize mailbox client
++ channel->cl.dev = rpdev->dev.parent;
++ channel->cl.rx_callback = arm_msg_rx_handler;
++ channel->cl.tx_done = NULL; /* operate in blocking mode */
++ channel->cl.tx_block = true;
++ channel->cl.tx_tout = 500; /* by half a second */
++ channel->cl.knows_txdone = false; /* depending upon protocol */
++
++ return &channel->ept;
+ }
+
+ static const struct rpmsg_device_ops arm_device_ops = {
+@@ -189,4 +149,3 @@ module_platform_driver(client_driver);
+ MODULE_LICENSE("GPL v2");
+ MODULE_DESCRIPTION("ARM RPMSG Driver");
+ MODULE_AUTHOR("Tushar Khandelwal <tushar.khandelwal@arm.com>");
+-
+--
+2.17.1
+
new file mode 100644
@@ -0,0 +1,107 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+
+From 451766a1eb1e070b585ab8cae31ed0dc7845a37a Mon Sep 17 00:00:00 2001
+From: Morten Borup Petersen <morten.petersen@arm.com>
+Date: Wed, 12 Jun 2019 12:11:57 +0100
+Subject: [PATCH 11/20] arm: couple mailbox channel ownership to rpmsg endpoint
+ lifecycle
+
+Previously, mailbox channels would be assigned once a write occured to the
+endpoint. This presents an issue wherein if a mailbox is opened with a given
+destination channel, and then read from, instead of writing to it, the target
+mailbox channel would not bind to the mailbox client, and thus not forward its
+received message to the rpmsg endpoint.
+
+This commits moves the ownership of a mailbox channel to the lifecycle of an
+rpmsg endpoint, thus registerring the mailbox channel with the mailbox client
+once the rpmsg endpoint is opened in userspace.
+
+Signed-off-by: Morten Borup Petersen <morten.petersen@arm.com>
+Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
+---
+ drivers/rpmsg/rpmsg_arm_mailbox.c | 31 +++++++++++++++----------------
+ 1 file changed, 15 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/rpmsg/rpmsg_arm_mailbox.c b/drivers/rpmsg/rpmsg_arm_mailbox.c
+index 4933187c61ea..0773b475a932 100644
+--- a/drivers/rpmsg/rpmsg_arm_mailbox.c
++++ b/drivers/rpmsg/rpmsg_arm_mailbox.c
+@@ -25,9 +25,9 @@
+ #define RPMSG_ADDR_ANY 0xFFFFFFFF
+
+ struct arm_channel {
+- struct rpmsg_channel_info chinfo;
+ struct rpmsg_endpoint ept;
+ struct mbox_client cl;
++ struct mbox_chan *mbox;
+ };
+
+ #define arm_channel_from_rpmsg(_ept) container_of(_ept, struct arm_channel, ept)
+@@ -37,29 +37,25 @@ struct arm_channel {
+ static void arm_msg_rx_handler(struct mbox_client *cl, void *mssg)
+ {
+ struct arm_channel* channel = arm_channel_from_mbox(cl);
+- channel->ept.cb(channel->ept.rpdev, mssg, 4, channel->ept.priv, RPMSG_ADDR_ANY);
++ int err = channel->ept.cb(channel->ept.rpdev, mssg, 4, channel->ept.priv, RPMSG_ADDR_ANY);
++ if(err) {
++ printk("ARM Mailbox: Endpoint callback failed with error: %d", err);
++ }
+ }
+
+
+ static void arm_destroy_ept(struct rpmsg_endpoint *ept)
+ {
+ struct arm_channel *channel = arm_channel_from_rpmsg(ept);
++ mbox_free_channel(channel->mbox);
+ kfree(channel);
+ }
+
+ static int arm_send(struct rpmsg_endpoint *ept, void *data, int len)
+ {
+ struct arm_channel *channel = arm_channel_from_rpmsg(ept);
+- struct mbox_chan *mbox;
+-
+- mbox = mbox_request_channel_byname(&channel->cl, channel->chinfo.name);
+- if (IS_ERR_OR_NULL(mbox)) {
+- printk("RPMsg ARM: Cannot get channel by name: '%s'\n", channel->chinfo.name);
+- return -1;
+- }
+
+- mbox_send_message(mbox, data);
+- mbox_free_channel(mbox);
++ mbox_send_message(channel->mbox, data);
+ return 0;
+ }
+
+@@ -72,12 +68,9 @@ static const struct rpmsg_endpoint_ops arm_endpoint_ops = {
+ static struct rpmsg_endpoint *arm_create_ept(struct rpmsg_device *rpdev,
+ rpmsg_rx_cb_t cb, void *priv, struct rpmsg_channel_info chinfo)
+ {
+- struct arm_channel* channel;
+- channel = kzalloc(sizeof(*channel), GFP_KERNEL);
++ struct arm_channel *channel;
+
+- // store chinfo for determining destination mailbox when sending
+- channel->chinfo = chinfo;
+- strncpy(channel->chinfo.name, chinfo.name, RPMSG_NAME_SIZE);
++ channel = kzalloc(sizeof(*channel), GFP_KERNEL);
+
+ // Initialize rpmsg endpoint
+ kref_init(&channel->ept.refcount);
+@@ -94,6 +87,12 @@ static struct rpmsg_endpoint *arm_create_ept(struct rpmsg_device *rpdev,
+ channel->cl.tx_tout = 500; /* by half a second */
+ channel->cl.knows_txdone = false; /* depending upon protocol */
+
++ channel->mbox = mbox_request_channel_byname(&channel->cl, chinfo.name);
++ if (IS_ERR_OR_NULL(channel->mbox)) {
++ printk("RPMsg ARM: Cannot get channel by name: '%s'\n", chinfo.name);
++ return -1;
++ }
++
+ return &channel->ept;
+ }
+
+--
+2.17.1
+
new file mode 100644
@@ -0,0 +1,36 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+
+From 546e8277f0a187bc32c1e60b4317c87ea6145f90 Mon Sep 17 00:00:00 2001
+From: Vishnu Banavath <vishnu.banavath@arm.com>
+Date: Fri, 16 Aug 2019 13:40:39 +0100
+Subject: [PATCH 12/20] mailbox: arm_mhu_v2: add new AMBA ID to support MHU
+ v2.1
+
+With MHU v2.1 specification, AMBA ID is changed.
+This change is to add a new AMBA ID entry for MHU.
+
+Signed-off-by: Vishnu Banavath <vishnu.banavath@arm.com>
+Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
+---
+ drivers/mailbox/arm_mhu_v2.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/mailbox/arm_mhu_v2.c b/drivers/mailbox/arm_mhu_v2.c
+index 7780958a16ab..fe43348db5e3 100644
+--- a/drivers/mailbox/arm_mhu_v2.c
++++ b/drivers/mailbox/arm_mhu_v2.c
+@@ -216,6 +216,10 @@ static struct amba_id mhuv2_ids[] = {
+ .id = 0xbb0d1,
+ .mask = 0xfffff,
+ },
++ {
++ .id = 0xbb076,
++ .mask = 0xfffff,
++ },
+ { 0, 0 },
+ };
+ MODULE_DEVICE_TABLE(amba, mhuv2_ids);
+--
+2.17.1
+
new file mode 100644
@@ -0,0 +1,119 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+
+From 4c0f31d0b6a10e9c67ca1e1a5cbae6511b087a51 Mon Sep 17 00:00:00 2001
+From: Vishnu Banavath <vishnu.banavath@arm.com>
+Date: Wed, 14 Aug 2019 18:02:11 +0100
+Subject: [PATCH 13/20] mailbox: arm_mhu_v2: dynamic allocation of channels
+
+Typically, hardware reports number of channels it supports.
+Software should read the appropriate registers to determine the
+number of channels support and should make the allocations
+accordingly. This change is to achieve it by removing static allocation
+and making dynamic allocations.
+
+Signed-off-by: Vishnu Banavath <vishnu.banavath@arm.com>
+Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
+---
+ drivers/mailbox/arm_mhu_v2.c | 47 +++++++++++++++++++++++++++---------
+ 1 file changed, 35 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/mailbox/arm_mhu_v2.c b/drivers/mailbox/arm_mhu_v2.c
+index fe43348db5e3..56fb31eeaa87 100644
+--- a/drivers/mailbox/arm_mhu_v2.c
++++ b/drivers/mailbox/arm_mhu_v2.c
+@@ -30,7 +30,7 @@
+ #define MHU_V2_CHCOMB BIT(2)
+ #define MHU_V2_AIDR_MINOR(_reg) ((_reg) & 0xF)
+
+-#define MHU_V2_CHANS 2
++#define MHU_V2_EACH_CHANNEL_SIZE 0x20
+
+ #define mbox_to_arm_mhuv2(c) container_of(c, struct arm_mhuv2, mbox)
+
+@@ -42,8 +42,8 @@ struct mhuv2_link {
+
+ struct arm_mhuv2 {
+ void __iomem *base;
+- struct mhuv2_link mlink[MHU_V2_CHANS];
+- struct mbox_chan chan[MHU_V2_CHANS];
++ struct mhuv2_link *mlink;
++ struct mbox_chan *chan;
+ struct mbox_controller mbox;
+ };
+
+@@ -140,6 +140,9 @@ static int mhuv2_probe(struct amba_device *adev, const struct amba_id *id)
+ void __iomem *rx_base, *tx_base;
+ const struct device_node *np = dev->of_node;
+ unsigned int pchans;
++ struct mhuv2_link *mlink;
++ struct mbox_chan *chan;
++
+
+ /* Allocate memory for device */
+ mhuv2 = devm_kzalloc(dev, sizeof(*mhuv2), GFP_KERNEL);
+@@ -159,25 +162,43 @@ static int mhuv2_probe(struct amba_device *adev, const struct amba_id *id)
+ return -ENOMEM;
+ }
+
+-
+ pchans = readl_relaxed(tx_base + MHU_V2_REG_MSG_NO_CAP_OFS);
+- if (pchans == 0 || pchans > MHU_V2_CHANS || pchans % 2) {
++ if (pchans == 0 || pchans % 2) {
+ dev_err(dev, "invalid number of channels %d\n", pchans);
+ iounmap(rx_base);
+ iounmap(tx_base);
+ return -EINVAL;
+ }
+- for (i = 0; i < pchans/2; i++) {
+- mhuv2->chan[i].con_priv = &mhuv2->mlink[i];
+- mhuv2->mlink[i].irq = adev->irq[i];
+- mhuv2->mlink[i].rx_reg = rx_base + i*0x4;
+- mhuv2->mlink[i].tx_reg = tx_base + i*0x4;
+- mhuv2_check_enable_cmbint(&mhuv2->mlink[i]);
++
++ mhuv2->mlink = devm_kcalloc(dev, pchans, sizeof(*mlink), GFP_KERNEL);
++ if (!mhuv2->mlink) {
++ iounmap(rx_base);
++ iounmap(tx_base);
++ return -ENOMEM;
++ }
++
++ mhuv2->chan = devm_kcalloc(dev, pchans, sizeof(*chan), GFP_KERNEL);
++ if (!mhuv2->chan) {
++ iounmap(rx_base);
++ iounmap(tx_base);
++ kfree(mhuv2->mlink);
++ return -ENOMEM;
+ }
+
++ for (i = 0; i < pchans; i++) {
++ mlink = mhuv2->mlink + i;
++ chan = mhuv2->chan + i;
++ chan->con_priv = mlink;
++ mlink->rx_reg = rx_base + (i * MHU_V2_EACH_CHANNEL_SIZE);
++ mlink->tx_reg = tx_base + (i * MHU_V2_EACH_CHANNEL_SIZE);
++ }
++
++ mhuv2->mlink->irq = adev->irq[0];
++ mhuv2_check_enable_cmbint(mhuv2->mlink);
++
+ mhuv2->base = tx_base;
+ mhuv2->mbox.dev = dev;
+- mhuv2->mbox.chans = &mhuv2->chan[0];
++ mhuv2->mbox.chans = mhuv2->chan;
+ mhuv2->mbox.num_chans = pchans;
+ mhuv2->mbox.ops = &mhuv2_ops;
+ mhuv2->mbox.txdone_irq = false;
+@@ -191,6 +212,8 @@ static int mhuv2_probe(struct amba_device *adev, const struct amba_id *id)
+ dev_err(dev, "failed to register mailboxes %d\n", err);
+ iounmap(rx_base);
+ iounmap(tx_base);
++ kfree(mhuv2->mlink);
++ kfree(mhuv2->chan);
+ return err;
+ }
+
+--
+2.17.1
+
new file mode 100644
@@ -0,0 +1,42 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+
+From eb92a2e53578326a15bc193c0dc2512793c8c502 Mon Sep 17 00:00:00 2001
+From: Vishnu Banavath <vishnu.banavath@arm.com>
+Date: Wed, 9 Oct 2019 13:28:51 +0100
+Subject: [PATCH 14/20] defconfig: adjust XIP physical address to 3MB offset
+
+Because of the memory constraint, reduced root filesystem
+to 2MB and as result XIP start address should be changed.
+This change is to adjust XIP PHYS start address to align
+with the rootfs size change
+
+Signed-off-by: Vishnu Banavath <vishnu.banavath@arm.com>
+Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
+---
+ arch/arm/configs/corstone700_defconfig | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/configs/corstone700_defconfig b/arch/arm/configs/corstone700_defconfig
+index 629b2163a534..61a0a3c3a209 100644
+--- a/arch/arm/configs/corstone700_defconfig
++++ b/arch/arm/configs/corstone700_defconfig
+@@ -25,7 +25,7 @@ CONFIG_PHYS_OFFSET=0x02100000
+ CONFIG_FLASH_MEM_BASE=0x08000000
+ CONFIG_FLASH_SIZE=0x4000000
+ CONFIG_XIP_KERNEL=y
+-CONFIG_XIP_PHYS_ADDR=0x08500000
++CONFIG_XIP_PHYS_ADDR=0x08300000
+ # CONFIG_ARCH_VEXPRESS_CA9X4=y
+ # CONFIG_ARCH_VEXPRESS_DCSCB=y
+ # CONFIG_ARCH_VEXPRESS_TC2_PM=y
+@@ -173,4 +173,4 @@ CONFIG_ARM_MHUv2=y
+ CONFIG_RPMSG=y
+ CONFIG_RPMSG_CHAR=y
+ CONFIG_RPMSG_ARM=y
+-CONFIG_EXTSYS_CTRL=y
+\ No newline at end of file
++CONFIG_EXTSYS_CTRL=y
+--
+2.17.1
+
new file mode 100644
@@ -0,0 +1,50 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+
+From dbf2cd8967b6e2c47084e52aae8a15a669614cb1 Mon Sep 17 00:00:00 2001
+From: Vishnu Banavath <vishnu.banavath@arm.com>
+Date: Mon, 7 Oct 2019 12:26:06 +0100
+Subject: [PATCH 15/20] arm: Kconfig: disable ARM_VIRT extension if XIP_KERNEL
+
+XIP is intended to execute kernel inplace and typically from
+flash and is used mostly on low memory devices.
+
+.macro store_primary_cpu_mode reg1, reg2, reg3
+ mrs \reg1, cpsr
+ and \reg1, \reg1, #MODE_MASK
+ adr \reg2, .L__boot_cpu_mode_offset
+ ldr \reg3, [\reg2]
+ str \reg1, [\reg2, \reg3]
+
+As text section is in flash memory and data section is in RAM.
+L__boot_cpu_mode_offset would evaluate to address based
+on virtual addresses provided by linker script. At this stage
+the MMU is OFF.
+
+The logic used based stored @L__boot_cpu_mode_offset on the offset
+between the boot_cpu_mode in data section and the location of
+L__boot_cpu_mode_offset can't be used along with PC to fetch the value
+of boot_cpu_mode doesn't work.
+
+This change is to disable CONFIG_ARM_VIRT_EXT for XIP kernel
+
+Signed-off-by: Vishnu Banavath <vishnu.banavath@arm.com>
+---
+ arch/arm/mm/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
+index 65e4482e3849..69810125998b 100644
+--- a/arch/arm/mm/Kconfig
++++ b/arch/arm/mm/Kconfig
+@@ -703,6 +703,7 @@ config ARM_THUMBEE
+
+ config ARM_VIRT_EXT
+ bool
++ depends on !XIP_KERNEL
+ default y if CPU_V7
+ help
+ Enable the kernel to make use of the ARM Virtualization
+--
+2.17.1
+
new file mode 100644
@@ -0,0 +1,34 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+
+From e5d99c1524576eb47c13e08d4dd20ebc72491477 Mon Sep 17 00:00:00 2001
+From: Vishnu Banavath <vishnu.banavath@arm.com>
+Date: Mon, 14 Oct 2019 15:15:46 +0100
+Subject: [PATCH 16/20] corstone700_defconfig: use DDR address instead of
+ shared RAM
+
+On fpga we use DDR for kernel data, dtb and rootfs.
+This change is to update CONFIG_PHYS_ADDR to 0x80000000
+
+Signed-off-by: Vishnu Banavath <vishnu.banavath@arm.com>
+Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
+---
+ arch/arm/configs/corstone700_defconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm/configs/corstone700_defconfig b/arch/arm/configs/corstone700_defconfig
+index 61a0a3c3a209..add9f5673395 100644
+--- a/arch/arm/configs/corstone700_defconfig
++++ b/arch/arm/configs/corstone700_defconfig
+@@ -21,7 +21,7 @@ CONFIG_BLK_DEV_INITRD=y
+ CONFIG_ARCH_TINY_VEXPRESS=y
+ CONFIG_ARM_SINGLE_ARMV7A=y
+ #CONFIG_DRAM_BASE=0x02100000
+-CONFIG_PHYS_OFFSET=0x02100000
++CONFIG_PHYS_OFFSET=0x80000000
+ CONFIG_FLASH_MEM_BASE=0x08000000
+ CONFIG_FLASH_SIZE=0x4000000
+ CONFIG_XIP_KERNEL=y
+--
+2.17.1
+
new file mode 100644
@@ -0,0 +1,61 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+
+From 32969f7963890fc0e3c7d47d788751272d95e501 Mon Sep 17 00:00:00 2001
+From: Rui Miguel Silva <rui.silva@linaro.org>
+Date: Fri, 20 Dec 2019 13:12:27 +0000
+Subject: [PATCH 17/20] corstone700_defconfig: enable configs for cramfs-xip
+
+Add the MTD and CRAMFS support for CramFS-XIP
+
+Because the NOR flash is already mapped and read-accessible
+before the kernel starts, so we don't need a QSPI driver to
+access the rootfs. The kernel shouldn't be configured with
+MTD_CFI. Otherwise, the kernel will verify CFI compliancy
+by writing commands to the flash and a QSPI driver is required
+in this case.
+
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
+---
+ arch/arm/configs/corstone700_defconfig | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/arch/arm/configs/corstone700_defconfig b/arch/arm/configs/corstone700_defconfig
+index add9f5673395..13863b804c6b 100644
+--- a/arch/arm/configs/corstone700_defconfig
++++ b/arch/arm/configs/corstone700_defconfig
+@@ -60,13 +60,17 @@ CONFIG_IP_PNP_BOOTP=y
+ # CONFIG_NET_9P_VIRTIO=y
+ # CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+ CONFIG_DEVTMPFS=y
+-# CONFIG_MTD=y
++CONFIG_MTD=y
+ # CONFIG_MTD_CMDLINE_PARTS=y
+ # CONFIG_MTD_BLOCK=y
+-# CONFIG_MTD_CFI=y
++CONFIG_MTD_RAM=y
++CONFIG_MTD_ROM=y
+ # CONFIG_MTD_CFI_INTELEXT=y
+ # CONFIG_MTD_CFI_AMDSTD=y
+-# CONFIG_MTD_PHYSMAP=y
++CONFIG_MTD_PHYSMAP=y
++CONFIG_MTD_PHYSMAP_COMPAT=y
++CONFIG_MTD_PHYSMAP_START=0x08100000
++CONFIG_MTD_PHYSMAP_LEN=0x200000
+ # CONFIG_MTD_PHYSMAP_OF=y
+ # CONFIG_MTD_PLATRAM=y
+ # CONFIG_MTD_UBI=y
+@@ -149,7 +153,8 @@ CONFIG_RTC_DRV_PL031=y
+ # CONFIG_TMPFS=y
+ # CONFIG_JFFS2_FS=y
+ # CONFIG_UBIFS_FS=y
+-# CONFIG_CRAMFS=y
++CONFIG_CRAMFS=y
++CONFIG_CRAMFS_MTD=y
+ # CONFIG_SQUASHFS=y
+ # CONFIG_SQUASHFS_LZO=y
+ # CONFIG_NFS_FS=y
+--
+2.17.1
+
new file mode 100644
@@ -0,0 +1,2297 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+
+From beba47e338d093f7fc08231b5b8039ad4db93494 Mon Sep 17 00:00:00 2001
+From: Rui Miguel Silva <rui.silva@linaro.org>
+Date: Thu, 25 Jun 2020 16:29:08 +0100
+Subject: [PATCH 18/20] usb: isp1760: move to regmap for register access
+
+Rework access to registers and memory to use regmap framework.
+No change in current feature or way of work is intended with this
+change.
+
+This will allow to reuse this driver with other IP of this family,
+for example isp1763, with little changes and effort.
+
+Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
+---
+ drivers/usb/isp1760/isp1760-core.c | 120 +++++---
+ drivers/usb/isp1760/isp1760-core.h | 38 ++-
+ drivers/usb/isp1760/isp1760-hcd.c | 434 ++++++++++++++--------------
+ drivers/usb/isp1760/isp1760-hcd.h | 16 +-
+ drivers/usb/isp1760/isp1760-if.c | 4 +-
+ drivers/usb/isp1760/isp1760-regs.h | 443 +++++++++++++++++------------
+ drivers/usb/isp1760/isp1760-udc.c | 235 ++++++++++-----
+ drivers/usb/isp1760/isp1760-udc.h | 10 +-
+ 8 files changed, 775 insertions(+), 525 deletions(-)
+
+diff --git a/drivers/usb/isp1760/isp1760-core.c b/drivers/usb/isp1760/isp1760-core.c
+index fdeb4cf97cc5..f7f680046a15 100644
+--- a/drivers/usb/isp1760/isp1760-core.c
++++ b/drivers/usb/isp1760/isp1760-core.c
+@@ -2,12 +2,14 @@
+ /*
+ * Driver for the NXP ISP1760 chip
+ *
++ * Copyright 2020 Rui Miguel Silva
+ * Copyright 2014 Laurent Pinchart
+ * Copyright 2007 Sebastian Siewior
+ *
+ * Contacts:
+ * Sebastian Siewior <bigeasy@linutronix.de>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Rui Miguel Silva <rmfrfs@gmail.com>
+ */
+
+ #include <linux/delay.h>
+@@ -25,8 +27,8 @@
+
+ static void isp1760_init_core(struct isp1760_device *isp)
+ {
+- u32 otgctrl;
+- u32 hwmode;
++ struct isp1760_hcd *hcd = &isp->hcd;
++ struct isp1760_udc *udc = &isp->udc;
+
+ /* Low-level chip reset */
+ if (isp->rst_gpio) {
+@@ -39,24 +41,22 @@ static void isp1760_init_core(struct isp1760_device *isp)
+ * Reset the host controller, including the CPU interface
+ * configuration.
+ */
+- isp1760_write32(isp->regs, HC_RESET_REG, SW_RESET_RESET_ALL);
++ isp1760_field_set(hcd->fields, SW_RESET_RESET_ALL);
+ msleep(100);
+
+ /* Setup HW Mode Control: This assumes a level active-low interrupt */
+- hwmode = HW_DATA_BUS_32BIT;
+-
+ if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_16)
+- hwmode &= ~HW_DATA_BUS_32BIT;
++ isp1760_field_clear(hcd->fields, HW_DATA_BUS_WIDTH);
+ if (isp->devflags & ISP1760_FLAG_ANALOG_OC)
+- hwmode |= HW_ANA_DIGI_OC;
++ isp1760_field_set(hcd->fields, HW_ANA_DIGI_OC);
+ if (isp->devflags & ISP1760_FLAG_DACK_POL_HIGH)
+- hwmode |= HW_DACK_POL_HIGH;
++ isp1760_field_set(hcd->fields, HW_DACK_POL_HIGH);
+ if (isp->devflags & ISP1760_FLAG_DREQ_POL_HIGH)
+- hwmode |= HW_DREQ_POL_HIGH;
++ isp1760_field_set(hcd->fields, HW_DREQ_POL_HIGH);
+ if (isp->devflags & ISP1760_FLAG_INTR_POL_HIGH)
+- hwmode |= HW_INTR_HIGH_ACT;
++ isp1760_field_set(hcd->fields, HW_INTR_HIGH_ACT);
+ if (isp->devflags & ISP1760_FLAG_INTR_EDGE_TRIG)
+- hwmode |= HW_INTR_EDGE_TRIG;
++ isp1760_field_set(hcd->fields, HW_INTR_EDGE_TRIG);
+
+ /*
+ * The ISP1761 has a dedicated DC IRQ line but supports sharing the HC
+@@ -65,18 +65,10 @@ static void isp1760_init_core(struct isp1760_device *isp)
+ * spurious interrupts during HCD registration.
+ */
+ if (isp->devflags & ISP1760_FLAG_ISP1761) {
+- isp1760_write32(isp->regs, DC_MODE, 0);
+- hwmode |= HW_COMN_IRQ;
++ isp1760_reg_write(udc->regs, ISP176x_DC_MODE, 0);
++ isp1760_field_set(hcd->fields, HW_COMN_IRQ);
+ }
+
+- /*
+- * We have to set this first in case we're in 16-bit mode.
+- * Write it twice to ensure correct upper bits if switching
+- * to 16-bit mode.
+- */
+- isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode);
+- isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode);
+-
+ /*
+ * PORT 1 Control register of the ISP1760 is the OTG control register
+ * on ISP1761.
+@@ -85,14 +77,15 @@ static void isp1760_init_core(struct isp1760_device *isp)
+ * when OTG is requested.
+ */
+ if ((isp->devflags & ISP1760_FLAG_ISP1761) &&
+- (isp->devflags & ISP1760_FLAG_OTG_EN))
+- otgctrl = ((HW_DM_PULLDOWN | HW_DP_PULLDOWN) << 16)
+- | HW_OTG_DISABLE;
+- else
+- otgctrl = (HW_SW_SEL_HC_DC << 16)
+- | (HW_VBUS_DRV | HW_SEL_CP_EXT);
+-
+- isp1760_write32(isp->regs, HC_PORT1_CTRL, otgctrl);
++ (isp->devflags & ISP1760_FLAG_OTG_EN)) {
++ isp1760_field_set(udc->fields, HW_DM_PULLDOWN);
++ isp1760_field_set(udc->fields, HW_DP_PULLDOWN);
++ isp1760_field_set(udc->fields, HW_OTG_DISABLE);
++ } else if (isp->devflags & ISP1760_FLAG_ISP1761) {
++ isp1760_field_set(udc->fields, HW_SW_SEL_HC_DC);
++ isp1760_field_set(udc->fields, HW_VBUS_DRV);
++ isp1760_field_set(udc->fields, HW_SEL_CP_EXT);
++ }
+
+ dev_info(isp->dev, "bus width: %u, oc: %s\n",
+ isp->devflags & ISP1760_FLAG_BUS_WIDTH_16 ? 16 : 32,
+@@ -101,16 +94,43 @@ static void isp1760_init_core(struct isp1760_device *isp)
+
+ void isp1760_set_pullup(struct isp1760_device *isp, bool enable)
+ {
+- isp1760_write32(isp->regs, HW_OTG_CTRL_SET,
+- enable ? HW_DP_PULLUP : HW_DP_PULLUP << 16);
++ struct isp1760_udc *udc = &isp->udc;
++
++ if (enable)
++ isp1760_field_set(udc->fields, HW_DP_PULLUP);
++ else
++ isp1760_field_set(udc->fields, HW_DP_PULLUP_CLEAR);
+ }
+
++static const struct regmap_config isp1760_hc_regmap_conf = {
++ .name = "isp1760-hc",
++ .reg_bits = 16,
++ .val_bits = 32,
++ .fast_io = true,
++ .max_register = ISP176x_HC_MEMORY,
++ .volatile_table = &isp176x_hc_volatile_table,
++};
++
++static const struct regmap_config isp1760_dc_regmap_conf = {
++ .name = "isp1760-dc",
++ .reg_bits = 16,
++ .val_bits = 32,
++ .fast_io = true,
++ .max_register = ISP1761_DC_OTG_CTRL_CLEAR,
++ .volatile_table = &isp176x_dc_volatile_table,
++};
++
+ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
+ struct device *dev, unsigned int devflags)
+ {
+ struct isp1760_device *isp;
++ struct isp1760_hcd *hcd;
++ struct isp1760_udc *udc;
+ bool udc_disabled = !(devflags & ISP1760_FLAG_ISP1761);
++ struct regmap_field *f;
++ void __iomem *base;
+ int ret;
++ int i;
+
+ /*
+ * If neither the HCD not the UDC is enabled return an error, as no
+@@ -126,19 +146,47 @@ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
+
+ isp->dev = dev;
+ isp->devflags = devflags;
++ hcd = &isp->hcd;
++ udc = &isp->udc;
+
+ isp->rst_gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH);
+ if (IS_ERR(isp->rst_gpio))
+ return PTR_ERR(isp->rst_gpio);
+
+- isp->regs = devm_ioremap_resource(dev, mem);
+- if (IS_ERR(isp->regs))
+- return PTR_ERR(isp->regs);
++ hcd->base = devm_ioremap_resource(dev, mem);
++ if (IS_ERR(hcd->base))
++ return PTR_ERR(hcd->base);
++
++ hcd->regs = devm_regmap_init_mmio(dev, base, &isp1760_hc_regmap_conf);
++ if (IS_ERR(hcd->regs))
++ return PTR_ERR(hcd->regs);
++
++ for (i = 0; i < HC_FIELD_MAX; i++) {
++ f = devm_regmap_field_alloc(dev, hcd->regs,
++ isp1760_hc_reg_fields[i]);
++ if (IS_ERR(f))
++ return PTR_ERR(f);
++
++ hcd->fields[i] = f;
++ }
++
++ udc->regs = devm_regmap_init_mmio(dev, base, &isp1760_dc_regmap_conf);
++ if (IS_ERR(udc->regs))
++ return PTR_ERR(udc->regs);
++
++ for (i = 0; i < DC_FIELD_MAX; i++) {
++ f = devm_regmap_field_alloc(dev, udc->regs,
++ isp1761_dc_reg_fields[i]);
++ if (IS_ERR(f))
++ return PTR_ERR(f);
++
++ udc->fields[i] = f;
++ }
+
+ isp1760_init_core(isp);
+
+ if (IS_ENABLED(CONFIG_USB_ISP1760_HCD) && !usb_disabled()) {
+- ret = isp1760_hcd_register(&isp->hcd, isp->regs, mem, irq,
++ ret = isp1760_hcd_register(hcd, mem, irq,
+ irqflags | IRQF_SHARED, dev);
+ if (ret < 0)
+ return ret;
+@@ -147,7 +195,7 @@ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
+ if (IS_ENABLED(CONFIG_USB_ISP1761_UDC) && !udc_disabled) {
+ ret = isp1760_udc_register(isp, irq, irqflags);
+ if (ret < 0) {
+- isp1760_hcd_unregister(&isp->hcd);
++ isp1760_hcd_unregister(hcd);
+ return ret;
+ }
+ }
+diff --git a/drivers/usb/isp1760/isp1760-core.h b/drivers/usb/isp1760/isp1760-core.h
+index 97cb4d7a3e1c..0cae69b4792c 100644
+--- a/drivers/usb/isp1760/isp1760-core.h
++++ b/drivers/usb/isp1760/isp1760-core.h
+@@ -14,6 +14,7 @@
+ #define _ISP1760_CORE_H_
+
+ #include <linux/ioport.h>
++#include <linux/regmap.h>
+
+ #include "isp1760-hcd.h"
+ #include "isp1760-udc.h"
+@@ -38,7 +39,6 @@ struct gpio_desc;
+ struct isp1760_device {
+ struct device *dev;
+
+- void __iomem *regs;
+ unsigned int devflags;
+ struct gpio_desc *rst_gpio;
+
+@@ -52,14 +52,42 @@ void isp1760_unregister(struct device *dev);
+
+ void isp1760_set_pullup(struct isp1760_device *isp, bool enable);
+
+-static inline u32 isp1760_read32(void __iomem *base, u32 reg)
++inline static u32 isp1760_field_read(struct regmap_field **fields, u32 field)
+ {
+- return readl(base + reg);
++ unsigned int val;
++
++ regmap_field_read(fields[field], &val);
++
++ return val;
++}
++
++inline static void isp1760_field_write(struct regmap_field **fields, u32 field,
++ u32 val)
++{
++ regmap_field_write(fields[field], val);
++}
++
++inline static void isp1760_field_set(struct regmap_field **fields, u32 field)
++{
++ isp1760_field_write(fields, field, 0xFFFFFFFF);
+ }
+
+-static inline void isp1760_write32(void __iomem *base, u32 reg, u32 val)
++inline static void isp1760_field_clear(struct regmap_field **fields, u32 field)
+ {
+- writel(val, base + reg);
++ isp1760_field_write(fields, field, 0);
+ }
+
++inline static u32 isp1760_reg_read(struct regmap *regs, u32 reg)
++{
++ unsigned int val;
++
++ regmap_read(regs, reg, &val);
++
++ return val;
++}
++
++inline static void isp1760_reg_write(struct regmap *regs, u32 reg, u32 val)
++{
++ regmap_write(regs, reg, val);
++}
+ #endif
+diff --git a/drivers/usb/isp1760/isp1760-hcd.c b/drivers/usb/isp1760/isp1760-hcd.c
+index 579a21bd70ad..76fed6e062ed 100644
+--- a/drivers/usb/isp1760/isp1760-hcd.c
++++ b/drivers/usb/isp1760/isp1760-hcd.c
+@@ -65,6 +65,10 @@ struct ptd {
+ #define ATL_PTD_OFFSET 0x0c00
+ #define PAYLOAD_OFFSET 0x1000
+
++#define ISP_BANK_0 0x00
++#define ISP_BANK_1 0x01
++#define ISP_BANK_2 0x02
++#define ISP_BANK_3 0x03
+
+ /* ATL */
+ /* DW0 */
+@@ -158,16 +162,59 @@ struct urb_listitem {
+ };
+
+ /*
+- * Access functions for isp176x registers (addresses 0..0x03FF).
++ * Access functions for isp176x registers regmap fields
+ */
+-static u32 reg_read32(void __iomem *base, u32 reg)
++static u32 isp1760_hcd_read(struct usb_hcd *hcd, u32 field)
+ {
+- return isp1760_read32(base, reg);
++ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++
++ return isp1760_field_read(priv->fields, field);
++}
++
++static void isp1760_hcd_write(struct usb_hcd *hcd, u32 field, u32 val)
++{
++ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++
++ isp1760_field_write(priv->fields, field, val);
++}
++
++static void isp1760_hcd_set(struct usb_hcd *hcd, u32 field)
++{
++ isp1760_hcd_write(hcd, field, 0xFFFFFFFF);
++}
++
++static void isp1760_hcd_clear(struct usb_hcd *hcd, u32 field)
++{
++ isp1760_hcd_write(hcd, field, 0);
++}
++
++static int isp1760_hcd_set_poll_timeout(struct usb_hcd *hcd, u32 field,
++ u32 timeout_us)
++{
++ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++ unsigned int val;
++
++ isp1760_hcd_set(hcd, field);
++
++ return regmap_field_read_poll_timeout(priv->fields[field], val, 1, 1,
++ timeout_us);
++}
++
++static int isp1760_hcd_clear_poll_timeout(struct usb_hcd *hcd, u32 field,
++ u32 timeout_us)
++{
++ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++ unsigned int val;
++
++ isp1760_hcd_clear(hcd, field);
++
++ return regmap_field_read_poll_timeout(priv->fields[field], val, 0, 1,
++ timeout_us);
+ }
+
+-static void reg_write32(void __iomem *base, u32 reg, u32 val)
++static bool isp1760_hcd_is_set(struct usb_hcd *hcd, u32 field)
+ {
+- isp1760_write32(base, reg, val);
++ return !!isp1760_hcd_read(hcd, field);
+ }
+
+ /*
+@@ -230,12 +277,15 @@ static void bank_reads8(void __iomem *src_base, u32 src_offset, u32 bank_addr,
+ }
+ }
+
+-static void mem_reads8(void __iomem *src_base, u32 src_offset, void *dst,
+- u32 bytes)
++static void mem_reads8(struct usb_hcd *hcd, void __iomem *src_base,
++ u32 src_offset, void *dst, u32 bytes)
+ {
+- reg_write32(src_base, HC_MEMORY_REG, src_offset + ISP_BANK(0));
++ isp1760_hcd_write(hcd, MEM_BANK_SEL, ISP_BANK_0);
++ isp1760_hcd_write(hcd, MEM_START_ADDR, src_offset);
++
+ ndelay(90);
+- bank_reads8(src_base, src_offset, ISP_BANK(0), dst, bytes);
++
++ bank_reads8(src_base, src_offset, ISP_BANK_0, dst, bytes);
+ }
+
+ static void mem_writes8(void __iomem *dst_base, u32 dst_offset,
+@@ -277,13 +327,14 @@ static void mem_writes8(void __iomem *dst_base, u32 dst_offset,
+ * Read and write ptds. 'ptd_offset' should be one of ISO_PTD_OFFSET,
+ * INT_PTD_OFFSET, and ATL_PTD_OFFSET. 'slot' should be less than 32.
+ */
+-static void ptd_read(void __iomem *base, u32 ptd_offset, u32 slot,
+- struct ptd *ptd)
++static void ptd_read(struct usb_hcd *hcd, void __iomem *base,
++ u32 ptd_offset, u32 slot, struct ptd *ptd)
+ {
+- reg_write32(base, HC_MEMORY_REG,
+- ISP_BANK(0) + ptd_offset + slot*sizeof(*ptd));
++ isp1760_hcd_write(hcd, MEM_BANK_SEL, ISP_BANK_0);
++ isp1760_hcd_write(hcd, MEM_START_ADDR,
++ ptd_offset + slot * sizeof(*ptd));
+ ndelay(90);
+- bank_reads8(base, ptd_offset + slot*sizeof(*ptd), ISP_BANK(0),
++ bank_reads8(base, ptd_offset + slot*sizeof(*ptd), ISP_BANK_0,
+ (void *) ptd, sizeof(*ptd));
+ }
+
+@@ -376,37 +427,15 @@ static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
+ qtd->payload_addr = 0;
+ }
+
+-static int handshake(struct usb_hcd *hcd, u32 reg,
+- u32 mask, u32 done, int usec)
+-{
+- u32 result;
+-
+- do {
+- result = reg_read32(hcd->regs, reg);
+- if (result == ~0)
+- return -ENODEV;
+- result &= mask;
+- if (result == done)
+- return 0;
+- udelay(1);
+- usec--;
+- } while (usec > 0);
+- return -ETIMEDOUT;
+-}
+-
+ /* reset a non-running (STS_HALT == 1) controller */
+ static int ehci_reset(struct usb_hcd *hcd)
+ {
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+- u32 command = reg_read32(hcd->regs, HC_USBCMD);
+-
+- command |= CMD_RESET;
+- reg_write32(hcd->regs, HC_USBCMD, command);
+ hcd->state = HC_STATE_HALT;
+ priv->next_statechange = jiffies;
+
+- return handshake(hcd, HC_USBCMD, CMD_RESET, 0, 250 * 1000);
++ return isp1760_hcd_set_poll_timeout(hcd, CMD_RESET, 250 * 1000);
+ }
+
+ static struct isp1760_qh *qh_alloc(gfp_t flags)
+@@ -434,8 +463,10 @@ static void qh_free(struct isp1760_qh *qh)
+ /* one-time init, only for memory state */
+ static int priv_init(struct usb_hcd *hcd)
+ {
+- struct isp1760_hcd *priv = hcd_to_priv(hcd);
+- u32 hcc_params;
++ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++ u32 isoc_cache;
++ u32 isoc_thres;
++
+ int i;
+
+ spin_lock_init(&priv->lock);
+@@ -450,12 +481,14 @@ static int priv_init(struct usb_hcd *hcd)
+ priv->periodic_size = DEFAULT_I_TDPS;
+
+ /* controllers may cache some of the periodic schedule ... */
+- hcc_params = reg_read32(hcd->regs, HC_HCCPARAMS);
++ isoc_cache = isp1760_hcd_read(hcd->regs, HCC_ISOC_CACHE);
++ isoc_thres = isp1760_hcd_read(hcd->regs, HCC_ISOC_THRES);
++
+ /* full frame cache */
+- if (HCC_ISOC_CACHE(hcc_params))
++ if (isoc_cache)
+ priv->i_thresh = 8;
+ else /* N microframes cached */
+- priv->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
++ priv->i_thresh = 2 + isoc_thres;
+
+ return 0;
+ }
+@@ -464,12 +497,13 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
+ {
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int result;
+- u32 scratch, hwmode;
++ u32 scratch;
++
++ isp1760_reg_write(priv->regs, ISP176x_HC_SCRATCH, 0xdeadbabe);
+
+- reg_write32(hcd->regs, HC_SCRATCH_REG, 0xdeadbabe);
+ /* Change bus pattern */
+- scratch = reg_read32(hcd->regs, HC_CHIP_ID_REG);
+- scratch = reg_read32(hcd->regs, HC_SCRATCH_REG);
++ scratch = isp1760_reg_read(priv->regs, ISP176x_HC_CHIP_ID);
++ scratch = isp1760_reg_read(priv->regs, ISP176x_HC_SCRATCH);
+ if (scratch != 0xdeadbabe) {
+ dev_err(hcd->self.controller, "Scratch test failed.\n");
+ return -ENODEV;
+@@ -483,10 +517,13 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
+ * the host controller through the EHCI USB Command register. The device
+ * has been reset in core code anyway, so this shouldn't matter.
+ */
+- reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, 0);
+- reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
+- reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
+- reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
++ isp1760_reg_write(priv->regs, ISP176x_HC_BUFFER_STATUS, 0);
++ isp1760_reg_write(priv->regs, ISP176x_HC_ATL_PTD_SKIPMAP,
++ NO_TRANSFER_ACTIVE);
++ isp1760_reg_write(priv->regs, ISP176x_HC_INT_PTD_SKIPMAP,
++ NO_TRANSFER_ACTIVE);
++ isp1760_reg_write(priv->regs, ISP176x_HC_ISO_PTD_SKIPMAP,
++ NO_TRANSFER_ACTIVE);
+
+ result = ehci_reset(hcd);
+ if (result)
+@@ -495,14 +532,11 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
+ /* Step 11 passed */
+
+ /* ATL reset */
+- hwmode = reg_read32(hcd->regs, HC_HW_MODE_CTRL) & ~ALL_ATX_RESET;
+- reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET);
++ isp1760_hcd_set(hcd, ALL_ATX_RESET);
+ mdelay(10);
+- reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
+-
+- reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, INTERRUPT_ENABLE_MASK);
++ isp1760_hcd_clear(hcd, ALL_ATX_RESET);
+
+- priv->hcs_params = reg_read32(hcd->regs, HC_HCSPARAMS);
++ isp1760_hcd_set(hcd, HC_INT_ENABLE);
+
+ return priv_init(hcd);
+ }
+@@ -732,12 +766,12 @@ static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot,
+
+ /* Make sure done map has not triggered from some unlinked transfer */
+ if (ptd_offset == ATL_PTD_OFFSET) {
+- priv->atl_done_map |= reg_read32(hcd->regs,
+- HC_ATL_PTD_DONEMAP_REG);
++ priv->atl_done_map |= isp1760_reg_read(priv->regs,
++ ISP176x_HC_ATL_PTD_DONEMAP);
+ priv->atl_done_map &= ~(1 << slot);
+ } else {
+- priv->int_done_map |= reg_read32(hcd->regs,
+- HC_INT_PTD_DONEMAP_REG);
++ priv->int_done_map |= isp1760_reg_read(priv->regs,
++ ISP176x_HC_INT_PTD_DONEMAP);
+ priv->int_done_map &= ~(1 << slot);
+ }
+
+@@ -746,16 +780,20 @@ static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot,
+ slots[slot].timestamp = jiffies;
+ slots[slot].qtd = qtd;
+ slots[slot].qh = qh;
+- ptd_write(hcd->regs, ptd_offset, slot, ptd);
++ ptd_write(priv->base, ptd_offset, slot, ptd);
+
+ if (ptd_offset == ATL_PTD_OFFSET) {
+- skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
++ skip_map = isp1760_reg_read(priv->regs,
++ ISP176x_HC_ATL_PTD_SKIPMAP);
+ skip_map &= ~(1 << qh->slot);
+- reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
++ isp1760_reg_write(priv->regs, ISP176x_HC_ATL_PTD_SKIPMAP,
++ skip_map);
+ } else {
+- skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
++ skip_map = isp1760_reg_read(priv->regs,
++ ISP176x_HC_INT_PTD_SKIPMAP);
+ skip_map &= ~(1 << qh->slot);
+- reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
++ isp1760_reg_write(priv->regs, ISP176x_HC_INT_PTD_SKIPMAP,
++ skip_map);
+ }
+ }
+
+@@ -768,9 +806,10 @@ static int is_short_bulk(struct isp1760_qtd *qtd)
+ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
+ struct list_head *urb_list)
+ {
+- int last_qtd;
++ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ struct isp1760_qtd *qtd, *qtd_next;
+ struct urb_listitem *urb_listitem;
++ int last_qtd;
+
+ list_for_each_entry_safe(qtd, qtd_next, &qh->qtd_list, qtd_list) {
+ if (qtd->status < QTD_XFER_COMPLETE)
+@@ -785,9 +824,10 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
+ if (qtd->actual_length) {
+ switch (qtd->packet_type) {
+ case IN_PID:
+- mem_reads8(hcd->regs, qtd->payload_addr,
+- qtd->data_buffer,
+- qtd->actual_length);
++ mem_reads8(hcd, priv->base,
++ qtd->payload_addr,
++ qtd->data_buffer,
++ qtd->actual_length);
+ /* Fall through */
+ case OUT_PID:
+ qtd->urb->actual_length +=
+@@ -875,7 +915,7 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
+ if ((qtd->length) &&
+ ((qtd->packet_type == SETUP_PID) ||
+ (qtd->packet_type == OUT_PID))) {
+- mem_writes8(hcd->regs, qtd->payload_addr,
++ mem_writes8(priv->base, qtd->payload_addr,
+ qtd->data_buffer, qtd->length);
+ }
+
+@@ -1076,9 +1116,9 @@ static void handle_done_ptds(struct usb_hcd *hcd)
+ int modified;
+ int skip_map;
+
+- skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
++ skip_map = isp1760_reg_read(priv->regs, ISP176x_HC_INT_PTD_SKIPMAP);
+ priv->int_done_map &= ~skip_map;
+- skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
++ skip_map = isp1760_reg_read(priv->regs, ISP176x_HC_ATL_PTD_SKIPMAP);
+ priv->atl_done_map &= ~skip_map;
+
+ modified = priv->int_done_map || priv->atl_done_map;
+@@ -1096,7 +1136,7 @@ static void handle_done_ptds(struct usb_hcd *hcd)
+ continue;
+ }
+ ptd_offset = INT_PTD_OFFSET;
+- ptd_read(hcd->regs, INT_PTD_OFFSET, slot, &ptd);
++ ptd_read(hcd, priv->base, INT_PTD_OFFSET, slot, &ptd);
+ state = check_int_transfer(hcd, &ptd,
+ slots[slot].qtd->urb);
+ } else {
+@@ -1111,7 +1151,7 @@ static void handle_done_ptds(struct usb_hcd *hcd)
+ continue;
+ }
+ ptd_offset = ATL_PTD_OFFSET;
+- ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
++ ptd_read(hcd, priv->base, ATL_PTD_OFFSET, slot, &ptd);
+ state = check_atl_transfer(hcd, &ptd,
+ slots[slot].qtd->urb);
+ }
+@@ -1212,13 +1252,15 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
+ if (!(hcd->state & HC_STATE_RUNNING))
+ goto leave;
+
+- imask = reg_read32(hcd->regs, HC_INTERRUPT_REG);
++ imask = isp1760_reg_read(priv->regs, ISP176x_HC_INTERRUPT);
+ if (unlikely(!imask))
+ goto leave;
+- reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */
++ isp1760_reg_write(priv->regs, ISP176x_HC_INTERRUPT, imask); /* Clear */
+
+- priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG);
+- priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG);
++ priv->int_done_map |= isp1760_reg_read(priv->regs,
++ ISP176x_HC_INT_PTD_DONEMAP);
++ priv->atl_done_map |= isp1760_reg_read(priv->regs,
++ ISP176x_HC_ATL_PTD_DONEMAP);
+
+ handle_done_ptds(hcd);
+
+@@ -1273,7 +1315,7 @@ static void errata2_function(struct timer_list *unused)
+ if (priv->atl_slots[slot].qh && time_after(jiffies,
+ priv->atl_slots[slot].timestamp +
+ msecs_to_jiffies(SLOT_TIMEOUT))) {
+- ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
++ ptd_read(hcd, priv->base, ATL_PTD_OFFSET, slot, &ptd);
+ if (!FROM_DW0_VALID(ptd.dw0) &&
+ !FROM_DW3_ACTIVE(ptd.dw3))
+ priv->atl_done_map |= 1 << slot;
+@@ -1290,9 +1332,8 @@ static void errata2_function(struct timer_list *unused)
+
+ static int isp1760_run(struct usb_hcd *hcd)
+ {
++ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int retval;
+- u32 temp;
+- u32 command;
+ u32 chipid;
+
+ hcd->uses_new_polling = 1;
+@@ -1300,23 +1341,20 @@ static int isp1760_run(struct usb_hcd *hcd)
+ hcd->state = HC_STATE_RUNNING;
+
+ /* Set PTD interrupt AND & OR maps */
+- reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0);
+- reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff);
+- reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0);
+- reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff);
+- reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0);
+- reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff);
++ isp1760_reg_write(priv->regs, ISP176x_HC_ATL_IRQ_MASK_AND, 0);
++ isp1760_reg_write(priv->regs, ISP176x_HC_ATL_IRQ_MASK_OR, 0xffffffff);
++ isp1760_reg_write(priv->regs, ISP176x_HC_INT_IRQ_MASK_AND, 0);
++ isp1760_reg_write(priv->regs, ISP176x_HC_INT_IRQ_MASK_OR, 0xffffffff);
++ isp1760_reg_write(priv->regs, ISP176x_HC_ISO_IRQ_MASK_AND, 0);
++ isp1760_reg_write(priv->regs, ISP176x_HC_ISO_IRQ_MASK_OR, 0xffffffff);
+ /* step 23 passed */
+
+- temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
+- reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN);
++ isp1760_hcd_set(hcd, HW_GLOBAL_INTR_EN);
+
+- command = reg_read32(hcd->regs, HC_USBCMD);
+- command &= ~(CMD_LRESET|CMD_RESET);
+- command |= CMD_RUN;
+- reg_write32(hcd->regs, HC_USBCMD, command);
++ isp1760_hcd_clear(hcd, CMD_LRESET);
++ isp1760_hcd_clear(hcd, CMD_RESET);
+
+- retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000);
++ retval = isp1760_hcd_set_poll_timeout(hcd, CMD_RUN, 250 * 1000);
+ if (retval)
+ return retval;
+
+@@ -1326,9 +1364,8 @@ static int isp1760_run(struct usb_hcd *hcd)
+ * the semaphore while doing so.
+ */
+ down_write(&ehci_cf_port_reset_rwsem);
+- reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF);
+
+- retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000);
++ retval = isp1760_hcd_set_poll_timeout(hcd, FLAG_CF, 250 * 1000);
+ up_write(&ehci_cf_port_reset_rwsem);
+ if (retval)
+ return retval;
+@@ -1338,21 +1375,22 @@ static int isp1760_run(struct usb_hcd *hcd)
+ errata2_timer.expires = jiffies + msecs_to_jiffies(SLOT_CHECK_PERIOD);
+ add_timer(&errata2_timer);
+
+- chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG);
++ chipid = isp1760_reg_read(priv->regs, ISP176x_HC_CHIP_ID);
+ dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n",
+ chipid & 0xffff, chipid >> 16);
+
+ /* PTD Register Init Part 2, Step 28 */
+
+ /* Setup registers controlling PTD checking */
+- reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000);
+- reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000);
+- reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001);
+- reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff);
+- reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff);
+- reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff);
+- reg_write32(hcd->regs, HC_BUFFER_STATUS_REG,
+- ATL_BUF_FILL | INT_BUF_FILL);
++ isp1760_reg_write(priv->regs, ISP176x_HC_ATL_PTD_LASTPTD, 0x80000000);
++ isp1760_reg_write(priv->regs, ISP176x_HC_INT_PTD_LASTPTD, 0x80000000);
++ isp1760_reg_write(priv->regs, ISP176x_HC_ISO_PTD_LASTPTD, 0x00000001);
++ isp1760_reg_write(priv->regs, ISP176x_HC_ATL_PTD_SKIPMAP, 0xffffffff);
++ isp1760_reg_write(priv->regs, ISP176x_HC_INT_PTD_SKIPMAP, 0xffffffff);
++ isp1760_reg_write(priv->regs, ISP176x_HC_ISO_PTD_SKIPMAP, 0xffffffff);
++
++ isp1760_hcd_set(hcd, ATL_BUF_FILL);
++ isp1760_hcd_set(hcd, INT_BUF_FILL);
+
+ /* GRR this is run-once init(), being done every time the HC starts.
+ * So long as they're part of class devices, we can't do it init()
+@@ -1586,15 +1624,19 @@ static void kill_transfer(struct usb_hcd *hcd, struct urb *urb,
+ /* We need to forcefully reclaim the slot since some transfers never
+ return, e.g. interrupt transfers and NAKed bulk transfers. */
+ if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) {
+- skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
++ skip_map = isp1760_reg_read(priv->regs,
++ ISP176x_HC_ATL_PTD_SKIPMAP);
+ skip_map |= (1 << qh->slot);
+- reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
++ isp1760_reg_write(priv->regs, ISP176x_HC_ATL_PTD_SKIPMAP,
++ skip_map);
+ priv->atl_slots[qh->slot].qh = NULL;
+ priv->atl_slots[qh->slot].qtd = NULL;
+ } else {
+- skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
++ skip_map = isp1760_reg_read(priv->regs,
++ ISP176x_HC_INT_PTD_SKIPMAP);
+ skip_map |= (1 << qh->slot);
+- reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
++ isp1760_reg_write(priv->regs, ISP176x_HC_INT_PTD_SKIPMAP,
++ skip_map);
+ priv->int_slots[qh->slot].qh = NULL;
+ priv->int_slots[qh->slot].qtd = NULL;
+ }
+@@ -1707,8 +1749,7 @@ static void isp1760_endpoint_disable(struct usb_hcd *hcd,
+ static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
+ {
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+- u32 temp, status = 0;
+- u32 mask;
++ u32 status = 0;
+ int retval = 1;
+ unsigned long flags;
+
+@@ -1718,17 +1759,13 @@ static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
+
+ /* init status to no-changes */
+ buf[0] = 0;
+- mask = PORT_CSC;
+
+ spin_lock_irqsave(&priv->lock, flags);
+- temp = reg_read32(hcd->regs, HC_PORTSC1);
+
+- if (temp & PORT_OWNER) {
+- if (temp & PORT_CSC) {
+- temp &= ~PORT_CSC;
+- reg_write32(hcd->regs, HC_PORTSC1, temp);
+- goto done;
+- }
++ if (isp1760_hcd_is_set(hcd, PORT_OWNER) &&
++ isp1760_hcd_is_set(hcd, PORT_CSC)) {
++ isp1760_hcd_clear(hcd, PORT_CSC);
++ goto done;
+ }
+
+ /*
+@@ -1737,11 +1774,9 @@ static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
+ * high-speed device is switched over to the companion
+ * controller by the user.
+ */
+-
+- if ((temp & mask) != 0
+- || ((temp & PORT_RESUME) != 0
+- && time_after_eq(jiffies,
+- priv->reset_done))) {
++ if (isp1760_hcd_is_set(hcd, PORT_CSC) ||
++ (isp1760_hcd_is_set(hcd, PORT_RESUME) &&
++ time_after_eq(jiffies, priv->reset_done))) {
+ buf [0] |= 1 << (0 + 1);
+ status = STS_PCD;
+ }
+@@ -1754,9 +1789,11 @@ static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
+ static void isp1760_hub_descriptor(struct isp1760_hcd *priv,
+ struct usb_hub_descriptor *desc)
+ {
+- int ports = HCS_N_PORTS(priv->hcs_params);
++ int ports;
+ u16 temp;
+
++ ports = isp1760_hcd_read(priv->hcd, HCS_N_PORTS);
++
+ desc->bDescriptorType = USB_DT_HUB;
+ /* priv 1.0, 2.3.9 says 20ms max */
+ desc->bPwrOn2PwrGood = 10;
+@@ -1772,7 +1809,7 @@ static void isp1760_hub_descriptor(struct isp1760_hcd *priv,
+
+ /* per-port overcurrent reporting */
+ temp = HUB_CHAR_INDV_PORT_OCPM;
+- if (HCS_PPC(priv->hcs_params))
++ if (isp1760_hcd_is_set(priv->hcd, HCS_PPC))
+ /* per-port power control */
+ temp |= HUB_CHAR_INDV_PORT_LPSM;
+ else
+@@ -1783,38 +1820,37 @@ static void isp1760_hub_descriptor(struct isp1760_hcd *priv,
+
+ #define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
+
+-static int check_reset_complete(struct usb_hcd *hcd, int index,
+- int port_status)
++static void check_reset_complete(struct usb_hcd *hcd, int index)
+ {
+- if (!(port_status & PORT_CONNECT))
+- return port_status;
++ if (!(isp1760_hcd_is_set(hcd, PORT_CONNECT)))
++ return;
+
+ /* if reset finished and it's still not enabled -- handoff */
+- if (!(port_status & PORT_PE)) {
+-
++ if (!isp1760_hcd_is_set(hcd, PORT_PE)) {
+ dev_info(hcd->self.controller,
+ "port %d full speed --> companion\n",
+ index + 1);
+
+- port_status |= PORT_OWNER;
+- port_status &= ~PORT_RWC_BITS;
+- reg_write32(hcd->regs, HC_PORTSC1, port_status);
++ isp1760_hcd_set(hcd, PORT_OWNER);
+
++ isp1760_hcd_clear(hcd, PORT_CSC);
+ } else
+ dev_info(hcd->self.controller, "port %d high speed\n",
+ index + 1);
+
+- return port_status;
++ return;
+ }
+
+ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ u16 wValue, u16 wIndex, char *buf, u16 wLength)
+ {
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+- int ports = HCS_N_PORTS(priv->hcs_params);
+- u32 temp, status;
++ u32 status;
+ unsigned long flags;
+ int retval = 0;
++ int ports;
++
++ ports = isp1760_hcd_read(hcd, HCS_N_PORTS);
+
+ /*
+ * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
+@@ -1839,7 +1875,6 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+- temp = reg_read32(hcd->regs, HC_PORTSC1);
+
+ /*
+ * Even if OWNER is set, so the port is owned by the
+@@ -1850,22 +1885,22 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+- reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_PE);
++ isp1760_hcd_clear(hcd, PORT_PE);
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ /* XXX error? */
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+- if (temp & PORT_RESET)
++ if (isp1760_hcd_is_set(hcd, PORT_RESET))
+ goto error;
+
+- if (temp & PORT_SUSPEND) {
+- if ((temp & PORT_PE) == 0)
++ if (isp1760_hcd_is_set(hcd, PORT_SUSPEND)) {
++ if (!isp1760_hcd_is_set(hcd, PORT_PE))
+ goto error;
+ /* resume signaling for 20 msec */
+- temp &= ~(PORT_RWC_BITS);
+- reg_write32(hcd->regs, HC_PORTSC1,
+- temp | PORT_RESUME);
++ isp1760_hcd_clear(hcd, PORT_CSC);
++ isp1760_hcd_set(hcd, PORT_RESUME);
++
+ priv->reset_done = jiffies +
+ msecs_to_jiffies(USB_RESUME_TIMEOUT);
+ }
+@@ -1874,12 +1909,11 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ /* we auto-clear this feature */
+ break;
+ case USB_PORT_FEAT_POWER:
+- if (HCS_PPC(priv->hcs_params))
+- reg_write32(hcd->regs, HC_PORTSC1,
+- temp & ~PORT_POWER);
++ if (isp1760_hcd_is_set(hcd, HCS_PPC))
++ isp1760_hcd_clear(hcd, PORT_POWER);
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
+- reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_CSC);
++ isp1760_hcd_set(hcd, PORT_CSC);
+ break;
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ /* XXX error ?*/
+@@ -1890,7 +1924,7 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ default:
+ goto error;
+ }
+- reg_read32(hcd->regs, HC_USBCMD);
++ isp1760_reg_read(priv->regs, ISP176x_HC_USBCMD);
+ break;
+ case GetHubDescriptor:
+ isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *)
+@@ -1905,15 +1939,14 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ goto error;
+ wIndex--;
+ status = 0;
+- temp = reg_read32(hcd->regs, HC_PORTSC1);
+
+ /* wPortChange bits */
+- if (temp & PORT_CSC)
++ if (isp1760_hcd_is_set(hcd, PORT_CSC))
+ status |= USB_PORT_STAT_C_CONNECTION << 16;
+
+
+ /* whoever resumes must GetPortStatus to complete it!! */
+- if (temp & PORT_RESUME) {
++ if (isp1760_hcd_is_set(hcd, PORT_RESUME)) {
+ dev_err(hcd->self.controller, "Port resume should be skipped.\n");
+
+ /* Remote Wakeup received? */
+@@ -1932,35 +1965,32 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ priv->reset_done = 0;
+
+ /* stop resume signaling */
+- temp = reg_read32(hcd->regs, HC_PORTSC1);
+- reg_write32(hcd->regs, HC_PORTSC1,
+- temp & ~(PORT_RWC_BITS | PORT_RESUME));
+- retval = handshake(hcd, HC_PORTSC1,
+- PORT_RESUME, 0, 2000 /* 2msec */);
++ isp1760_hcd_clear(hcd, PORT_CSC);
++
++ retval = isp1760_hcd_clear_poll_timeout(hcd,
++ PORT_RESUME, 2000);
+ if (retval != 0) {
+ dev_err(hcd->self.controller,
+ "port %d resume error %d\n",
+ wIndex + 1, retval);
+ goto error;
+ }
+- temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
+ }
+ }
+
+ /* whoever resets must GetPortStatus to complete it!! */
+- if ((temp & PORT_RESET)
+- && time_after_eq(jiffies,
+- priv->reset_done)) {
++ if (isp1760_hcd_is_set(hcd, PORT_RESET)
++ && time_after_eq(jiffies, priv->reset_done)) {
+ status |= USB_PORT_STAT_C_RESET << 16;
+ priv->reset_done = 0;
+
+ /* force reset to complete */
+- reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_RESET);
+ /* REVISIT: some hardware needs 550+ usec to clear
+ * this bit; seems too long to spin routinely...
+ */
+- retval = handshake(hcd, HC_PORTSC1,
+- PORT_RESET, 0, 750);
++ retval = isp1760_hcd_clear_poll_timeout(hcd,
++ PORT_RESET,
++ 750);
+ if (retval != 0) {
+ dev_err(hcd->self.controller, "port %d reset error %d\n",
+ wIndex + 1, retval);
+@@ -1968,8 +1998,7 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ }
+
+ /* see what we found out */
+- temp = check_reset_complete(hcd, wIndex,
+- reg_read32(hcd->regs, HC_PORTSC1));
++ check_reset_complete(hcd, wIndex);
+ }
+ /*
+ * Even if OWNER is set, there's no harm letting hub_wq
+@@ -1977,21 +2006,22 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ * for PORT_POWER anyway).
+ */
+
+- if (temp & PORT_OWNER)
++ if (isp1760_hcd_is_set(hcd, PORT_OWNER))
+ dev_err(hcd->self.controller, "PORT_OWNER is set\n");
+
+- if (temp & PORT_CONNECT) {
++ if (isp1760_hcd_is_set(hcd, PORT_CONNECT)) {
+ status |= USB_PORT_STAT_CONNECTION;
+ /* status may be from integrated TT */
+ status |= USB_PORT_STAT_HIGH_SPEED;
+ }
+- if (temp & PORT_PE)
++ if (isp1760_hcd_is_set(hcd, PORT_PE))
+ status |= USB_PORT_STAT_ENABLE;
+- if (temp & (PORT_SUSPEND|PORT_RESUME))
++ if (isp1760_hcd_is_set(hcd, PORT_SUSPEND) &&
++ isp1760_hcd_is_set(hcd, PORT_RESUME))
+ status |= USB_PORT_STAT_SUSPEND;
+- if (temp & PORT_RESET)
++ if (isp1760_hcd_is_set(hcd, PORT_RESET))
+ status |= USB_PORT_STAT_RESET;
+- if (temp & PORT_POWER)
++ if (isp1760_hcd_is_set(hcd, PORT_POWER))
+ status |= USB_PORT_STAT_POWER;
+
+ put_unaligned(cpu_to_le32(status), (__le32 *) buf);
+@@ -2011,41 +2041,39 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+- temp = reg_read32(hcd->regs, HC_PORTSC1);
+- if (temp & PORT_OWNER)
++ if (isp1760_hcd_is_set(hcd, PORT_OWNER))
+ break;
+
+-/* temp &= ~PORT_RWC_BITS; */
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+- reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_PE);
++ isp1760_hcd_set(hcd, PORT_PE);
+ break;
+
+ case USB_PORT_FEAT_SUSPEND:
+- if ((temp & PORT_PE) == 0
+- || (temp & PORT_RESET) != 0)
++ if (!isp1760_hcd_is_set(hcd, PORT_PE)
++ || isp1760_hcd_is_set(hcd, PORT_RESET))
+ goto error;
+
+- reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_SUSPEND);
++ isp1760_hcd_set(hcd, PORT_SUSPEND);
+ break;
+ case USB_PORT_FEAT_POWER:
+- if (HCS_PPC(priv->hcs_params))
+- reg_write32(hcd->regs, HC_PORTSC1,
+- temp | PORT_POWER);
++ if (isp1760_hcd_is_set(hcd, HCS_PPC))
++ isp1760_hcd_set(hcd, PORT_POWER);
+ break;
+ case USB_PORT_FEAT_RESET:
+- if (temp & PORT_RESUME)
++ if (isp1760_hcd_is_set(hcd, PORT_RESUME))
+ goto error;
+ /* line status bits may report this as low speed,
+ * which can be fine if this root hub has a
+ * transaction translator built in.
+ */
+- if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
+- && PORT_USB11(temp)) {
+- temp |= PORT_OWNER;
++ if ((isp1760_hcd_is_set(hcd, PORT_CONNECT) &&
++ !isp1760_hcd_is_set(hcd, PORT_PE)) &&
++ (isp1760_hcd_read(hcd, PORT_LSTATUS) == 1)) {
++ isp1760_hcd_set(hcd, PORT_OWNER);
+ } else {
+- temp |= PORT_RESET;
+- temp &= ~PORT_PE;
++ isp1760_hcd_set(hcd, PORT_RESET);
++ isp1760_hcd_clear(hcd, PORT_PE);
+
+ /*
+ * caller must wait, then call GetPortStatus
+@@ -2054,12 +2082,11 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ priv->reset_done = jiffies +
+ msecs_to_jiffies(50);
+ }
+- reg_write32(hcd->regs, HC_PORTSC1, temp);
+ break;
+ default:
+ goto error;
+ }
+- reg_read32(hcd->regs, HC_USBCMD);
++ isp1760_reg_read(priv->regs, ISP176x_HC_USBCMD);
+ break;
+
+ default:
+@@ -2076,14 +2103,13 @@ static int isp1760_get_frame(struct usb_hcd *hcd)
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 fr;
+
+- fr = reg_read32(hcd->regs, HC_FRINDEX);
++ fr = isp1760_hcd_read(hcd, HC_FRINDEX);
+ return (fr >> 3) % priv->periodic_size;
+ }
+
+ static void isp1760_stop(struct usb_hcd *hcd)
+ {
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+- u32 temp;
+
+ del_timer(&errata2_timer);
+
+@@ -2094,24 +2120,19 @@ static void isp1760_stop(struct usb_hcd *hcd)
+ spin_lock_irq(&priv->lock);
+ ehci_reset(hcd);
+ /* Disable IRQ */
+- temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
+- reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN);
++ isp1760_hcd_clear(hcd, HW_GLOBAL_INTR_EN);
+ spin_unlock_irq(&priv->lock);
+
+- reg_write32(hcd->regs, HC_CONFIGFLAG, 0);
++ isp1760_hcd_clear(hcd, FLAG_CF);
+ }
+
+ static void isp1760_shutdown(struct usb_hcd *hcd)
+ {
+- u32 command, temp;
+-
+ isp1760_stop(hcd);
+- temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
+- reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN);
+
+- command = reg_read32(hcd->regs, HC_USBCMD);
+- command &= ~CMD_RUN;
+- reg_write32(hcd->regs, HC_USBCMD, command);
++ isp1760_hcd_clear(hcd, HW_GLOBAL_INTR_EN);
++
++ isp1760_hcd_clear(hcd, CMD_RUN);
+ }
+
+ static void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd,
+@@ -2184,8 +2205,8 @@ void isp1760_deinit_kmem_cache(void)
+ kmem_cache_destroy(urb_listitem_cachep);
+ }
+
+-int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs,
+- struct resource *mem, int irq, unsigned long irqflags,
++int isp1760_hcd_register(struct isp1760_hcd *priv, struct resource *mem,
++ int irq, unsigned long irqflags,
+ struct device *dev)
+ {
+ struct usb_hcd *hcd;
+@@ -2202,7 +2223,6 @@ int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs,
+ init_memory(priv);
+
+ hcd->irq = irq;
+- hcd->regs = regs;
+ hcd->rsrc_start = mem->start;
+ hcd->rsrc_len = resource_size(mem);
+
+diff --git a/drivers/usb/isp1760/isp1760-hcd.h b/drivers/usb/isp1760/isp1760-hcd.h
+index f1bb2deb1ccf..7a1f4f2607be 100644
+--- a/drivers/usb/isp1760/isp1760-hcd.h
++++ b/drivers/usb/isp1760/isp1760-hcd.h
+@@ -3,6 +3,9 @@
+ #define _ISP1760_HCD_H_
+
+ #include <linux/spinlock.h>
++#include <linux/regmap.h>
++
++#include "isp1760-regs.h"
+
+ struct isp1760_qh;
+ struct isp1760_qtd;
+@@ -51,7 +54,11 @@ struct isp1760_hcd {
+ #ifdef CONFIG_USB_ISP1760_HCD
+ struct usb_hcd *hcd;
+
+- u32 hcs_params;
++ void __iomem *base;
++
++ struct regmap *regs;
++ struct regmap_field *fields[HC_FIELD_MAX];
++
+ spinlock_t lock;
+ struct isp1760_slotinfo atl_slots[32];
+ int atl_done_map;
+@@ -70,16 +77,15 @@ struct isp1760_hcd {
+ };
+
+ #ifdef CONFIG_USB_ISP1760_HCD
+-int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs,
+- struct resource *mem, int irq, unsigned long irqflags,
+- struct device *dev);
++int isp1760_hcd_register(struct isp1760_hcd *priv, struct resource *mem,
++ int irq, unsigned long irqflags, struct device *dev);
+ void isp1760_hcd_unregister(struct isp1760_hcd *priv);
+
+ int isp1760_init_kmem_once(void);
+ void isp1760_deinit_kmem_cache(void);
+ #else
+ static inline int isp1760_hcd_register(struct isp1760_hcd *priv,
+- void __iomem *regs, struct resource *mem,
++ struct resource *mem,
+ int irq, unsigned long irqflags,
+ struct device *dev)
+ {
+diff --git a/drivers/usb/isp1760/isp1760-if.c b/drivers/usb/isp1760/isp1760-if.c
+index ccd30f835888..abfba9f5ec23 100644
+--- a/drivers/usb/isp1760/isp1760-if.c
++++ b/drivers/usb/isp1760/isp1760-if.c
+@@ -75,9 +75,9 @@ static int isp1761_pci_init(struct pci_dev *dev)
+ /*by default host is in 16bit mode, so
+ * io operations at this stage must be 16 bit
+ * */
+- writel(0xface, iobase + HC_SCRATCH_REG);
++ writel(0xface, iobase + ISP176x_HC_SCRATCH);
+ udelay(100);
+- reg_data = readl(iobase + HC_SCRATCH_REG) & 0x0000ffff;
++ reg_data = readl(iobase + ISP176x_HC_SCRATCH) & 0x0000ffff;
+ retry_count--;
+ }
+
+diff --git a/drivers/usb/isp1760/isp1760-regs.h b/drivers/usb/isp1760/isp1760-regs.h
+index 1f00c3850cf7..4e835e9665bd 100644
+--- a/drivers/usb/isp1760/isp1760-regs.h
++++ b/drivers/usb/isp1760/isp1760-regs.h
+@@ -10,218 +10,287 @@
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ */
+
+-#ifndef _ISP1760_REGS_H_
+-#define _ISP1760_REGS_H_
++#ifndef _ISP176x_REGS_H_
++#define _ISP176x_REGS_H_
++
++#include <linux/regmap.h>
+
+ /* -----------------------------------------------------------------------------
+ * Host Controller
+ */
+
+ /* EHCI capability registers */
+-#define HC_CAPLENGTH 0x000
+-#define HC_LENGTH(p) (((p) >> 00) & 0x00ff) /* bits 7:0 */
+-#define HC_VERSION(p) (((p) >> 16) & 0xffff) /* bits 31:16 */
+-
+-#define HC_HCSPARAMS 0x004
+-#define HCS_INDICATOR(p) ((p) & (1 << 16)) /* true: has port indicators */
+-#define HCS_PPC(p) ((p) & (1 << 4)) /* true: port power control */
+-#define HCS_N_PORTS(p) (((p) >> 0) & 0xf) /* bits 3:0, ports on HC */
+-
+-#define HC_HCCPARAMS 0x008
+-#define HCC_ISOC_CACHE(p) ((p) & (1 << 7)) /* true: can cache isoc frame */
+-#define HCC_ISOC_THRES(p) (((p) >> 4) & 0x7) /* bits 6:4, uframes cached */
++#define ISP176x_HC_CAPLENGTH 0x000
++#define ISP176x_HC_VERSION 0x002
++#define ISP176x_HC_HCSPARAMS 0x004
++#define ISP176x_HC_HCCPARAMS 0x008
+
+ /* EHCI operational registers */
+-#define HC_USBCMD 0x020
+-#define CMD_LRESET (1 << 7) /* partial reset (no ports, etc) */
+-#define CMD_RESET (1 << 1) /* reset HC not bus */
+-#define CMD_RUN (1 << 0) /* start/stop HC */
+-
+-#define HC_USBSTS 0x024
+-#define STS_PCD (1 << 2) /* port change detect */
+-
+-#define HC_FRINDEX 0x02c
+-
+-#define HC_CONFIGFLAG 0x060
+-#define FLAG_CF (1 << 0) /* true: we'll support "high speed" */
+-
+-#define HC_PORTSC1 0x064
+-#define PORT_OWNER (1 << 13) /* true: companion hc owns this port */
+-#define PORT_POWER (1 << 12) /* true: has power (see PPC) */
+-#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */
+-#define PORT_RESET (1 << 8) /* reset port */
+-#define PORT_SUSPEND (1 << 7) /* suspend port */
+-#define PORT_RESUME (1 << 6) /* resume it */
+-#define PORT_PE (1 << 2) /* port enable */
+-#define PORT_CSC (1 << 1) /* connect status change */
+-#define PORT_CONNECT (1 << 0) /* device connected */
+-#define PORT_RWC_BITS (PORT_CSC)
+-
+-#define HC_ISO_PTD_DONEMAP_REG 0x130
+-#define HC_ISO_PTD_SKIPMAP_REG 0x134
+-#define HC_ISO_PTD_LASTPTD_REG 0x138
+-#define HC_INT_PTD_DONEMAP_REG 0x140
+-#define HC_INT_PTD_SKIPMAP_REG 0x144
+-#define HC_INT_PTD_LASTPTD_REG 0x148
+-#define HC_ATL_PTD_DONEMAP_REG 0x150
+-#define HC_ATL_PTD_SKIPMAP_REG 0x154
+-#define HC_ATL_PTD_LASTPTD_REG 0x158
++#define ISP176x_HC_USBCMD 0x020
++#define ISP176x_HC_USBSTS 0x024
++#define ISP176x_HC_FRINDEX 0x02c
++
++#define ISP176x_HC_CONFIGFLAG 0x060
++#define ISP176x_HC_PORTSC1 0x064
++
++#define ISP176x_HC_ISO_PTD_DONEMAP 0x130
++#define ISP176x_HC_ISO_PTD_SKIPMAP 0x134
++#define ISP176x_HC_ISO_PTD_LASTPTD 0x138
++#define ISP176x_HC_INT_PTD_DONEMAP 0x140
++#define ISP176x_HC_INT_PTD_SKIPMAP 0x144
++#define ISP176x_HC_INT_PTD_LASTPTD 0x148
++#define ISP176x_HC_ATL_PTD_DONEMAP 0x150
++#define ISP176x_HC_ATL_PTD_SKIPMAP 0x154
++#define ISP176x_HC_ATL_PTD_LASTPTD 0x158
+
+ /* Configuration Register */
+-#define HC_HW_MODE_CTRL 0x300
+-#define ALL_ATX_RESET (1 << 31)
+-#define HW_ANA_DIGI_OC (1 << 15)
+-#define HW_DEV_DMA (1 << 11)
+-#define HW_COMN_IRQ (1 << 10)
+-#define HW_COMN_DMA (1 << 9)
+-#define HW_DATA_BUS_32BIT (1 << 8)
+-#define HW_DACK_POL_HIGH (1 << 6)
+-#define HW_DREQ_POL_HIGH (1 << 5)
+-#define HW_INTR_HIGH_ACT (1 << 2)
+-#define HW_INTR_EDGE_TRIG (1 << 1)
+-#define HW_GLOBAL_INTR_EN (1 << 0)
+-
+-#define HC_CHIP_ID_REG 0x304
+-#define HC_SCRATCH_REG 0x308
+-
+-#define HC_RESET_REG 0x30c
+-#define SW_RESET_RESET_HC (1 << 1)
+-#define SW_RESET_RESET_ALL (1 << 0)
+-
+-#define HC_BUFFER_STATUS_REG 0x334
+-#define ISO_BUF_FILL (1 << 2)
+-#define INT_BUF_FILL (1 << 1)
+-#define ATL_BUF_FILL (1 << 0)
+-
+-#define HC_MEMORY_REG 0x33c
+-#define ISP_BANK(x) ((x) << 16)
+-
+-#define HC_PORT1_CTRL 0x374
+-#define PORT1_POWER (3 << 3)
+-#define PORT1_INIT1 (1 << 7)
+-#define PORT1_INIT2 (1 << 23)
+-#define HW_OTG_CTRL_SET 0x374
+-#define HW_OTG_CTRL_CLR 0x376
+-#define HW_OTG_DISABLE (1 << 10)
+-#define HW_OTG_SE0_EN (1 << 9)
+-#define HW_BDIS_ACON_EN (1 << 8)
+-#define HW_SW_SEL_HC_DC (1 << 7)
+-#define HW_VBUS_CHRG (1 << 6)
+-#define HW_VBUS_DISCHRG (1 << 5)
+-#define HW_VBUS_DRV (1 << 4)
+-#define HW_SEL_CP_EXT (1 << 3)
+-#define HW_DM_PULLDOWN (1 << 2)
+-#define HW_DP_PULLDOWN (1 << 1)
+-#define HW_DP_PULLUP (1 << 0)
++#define ISP176x_HC_HW_MODE_CTRL 0x300
++#define ISP176x_HC_CHIP_ID 0x304
++#define ISP176x_HC_SCRATCH 0x308
++#define ISP176x_HC_RESET 0x30c
++#define ISP176x_HC_BUFFER_STATUS 0x334
++#define ISP176x_HC_MEMORY 0x33c
+
+ /* Interrupt Register */
+-#define HC_INTERRUPT_REG 0x310
+-
+-#define HC_INTERRUPT_ENABLE 0x314
+-#define HC_ISO_INT (1 << 9)
+-#define HC_ATL_INT (1 << 8)
+-#define HC_INTL_INT (1 << 7)
+-#define HC_EOT_INT (1 << 3)
+-#define HC_SOT_INT (1 << 1)
+-#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT)
+-
+-#define HC_ISO_IRQ_MASK_OR_REG 0x318
+-#define HC_INT_IRQ_MASK_OR_REG 0x31c
+-#define HC_ATL_IRQ_MASK_OR_REG 0x320
+-#define HC_ISO_IRQ_MASK_AND_REG 0x324
+-#define HC_INT_IRQ_MASK_AND_REG 0x328
+-#define HC_ATL_IRQ_MASK_AND_REG 0x32c
++#define ISP176x_HC_INTERRUPT 0x310
++#define ISP176x_HC_INTERRUPT_ENABLE 0x314
++#define ISP176x_HC_ISO_IRQ_MASK_OR 0x318
++#define ISP176x_HC_INT_IRQ_MASK_OR 0x31c
++#define ISP176x_HC_ATL_IRQ_MASK_OR 0x320
++#define ISP176x_HC_ISO_IRQ_MASK_AND 0x324
++#define ISP176x_HC_INT_IRQ_MASK_AND 0x328
++#define ISP176x_HC_ATL_IRQ_MASK_AND 0x32c
++
++
++static const struct regmap_range isp176x_hc_volatile_ranges[] = {
++ regmap_reg_range(ISP176x_HC_USBCMD, ISP176x_HC_ATL_PTD_LASTPTD),
++ regmap_reg_range(ISP176x_HC_BUFFER_STATUS, ISP176x_HC_MEMORY),
++ regmap_reg_range(ISP176x_HC_INTERRUPT, ISP176x_HC_ATL_IRQ_MASK_AND),
++};
++
++static const struct regmap_access_table isp176x_hc_volatile_table = {
++ .yes_ranges = isp176x_hc_volatile_ranges,
++ .n_yes_ranges = ARRAY_SIZE(isp176x_hc_volatile_ranges),
++};
++
++enum isp176x_host_controller_fields {
++ /* HC_HCSPARAMS */
++ HCS_PPC, HCS_N_PORTS,
++ /* HC_HCCPARAMS */
++ HCC_ISOC_CACHE, HCC_ISOC_THRES,
++ /* HC_USBCMD */
++ CMD_LRESET, CMD_RESET, CMD_RUN,
++ /* HC_USBSTS */
++ STS_PCD,
++ /* HC_FRINDEX */
++ HC_FRINDEX,
++ /* HC_CONFIGFLAG */
++ FLAG_CF,
++ /* HC_PORTSC1 */
++ PORT_OWNER, PORT_POWER, PORT_LSTATUS, PORT_RESET, PORT_SUSPEND,
++ PORT_RESUME, PORT_PE, PORT_CSC, PORT_CONNECT,
++ /* HC_HW_MODE_CTRL */
++ ALL_ATX_RESET, HW_ANA_DIGI_OC, HW_DEV_DMA, HW_COMN_IRQ, HW_COMN_DMA,
++ HW_DATA_BUS_WIDTH, HW_DACK_POL_HIGH, HW_DREQ_POL_HIGH, HW_INTR_HIGH_ACT,
++ HW_INTR_EDGE_TRIG, HW_GLOBAL_INTR_EN,
++ /* HC_RESET */
++ SW_RESET_RESET_HC, SW_RESET_RESET_ALL,
++ /* HC_BUFFER_STATUS */
++ INT_BUF_FILL, ATL_BUF_FILL,
++ /* HC_MEMORY */
++ MEM_BANK_SEL, MEM_START_ADDR,
++ /* HC_INTERRUPT_ENABLE */
++ HC_INT_ENABLE,
++ /* Last element */
++ HC_FIELD_MAX,
++};
++
++static const struct reg_field isp1760_hc_reg_fields[] = {
++ [HCS_PPC] = REG_FIELD(ISP176x_HC_HCSPARAMS, 4, 4),
++ [HCS_N_PORTS] = REG_FIELD(ISP176x_HC_HCSPARAMS, 0, 3),
++ [HCC_ISOC_CACHE] = REG_FIELD(ISP176x_HC_HCCPARAMS, 7, 7),
++ [HCC_ISOC_THRES] = REG_FIELD(ISP176x_HC_HCCPARAMS, 4, 6),
++ [CMD_LRESET] = REG_FIELD(ISP176x_HC_USBCMD, 7, 7),
++ [CMD_RESET] = REG_FIELD(ISP176x_HC_USBCMD, 1, 1),
++ [CMD_RUN] = REG_FIELD(ISP176x_HC_USBCMD, 0, 0),
++ [STS_PCD] = REG_FIELD(ISP176x_HC_USBSTS, 2, 2),
++ [HC_FRINDEX] = REG_FIELD(ISP176x_HC_FRINDEX, 0, 13),
++ [FLAG_CF] = REG_FIELD(ISP176x_HC_CONFIGFLAG, 0, 0),
++ [PORT_OWNER] = REG_FIELD(ISP176x_HC_PORTSC1, 13, 13),
++ [PORT_POWER] = REG_FIELD(ISP176x_HC_PORTSC1, 12, 12),
++ [PORT_LSTATUS] = REG_FIELD(ISP176x_HC_PORTSC1, 10, 11),
++ [PORT_RESET] = REG_FIELD(ISP176x_HC_PORTSC1, 8, 8),
++ [PORT_SUSPEND] = REG_FIELD(ISP176x_HC_PORTSC1, 7, 7),
++ [PORT_RESUME] = REG_FIELD(ISP176x_HC_PORTSC1, 6, 6),
++ [PORT_PE] = REG_FIELD(ISP176x_HC_PORTSC1, 2, 2),
++ [PORT_CSC] = REG_FIELD(ISP176x_HC_PORTSC1, 1, 1),
++ [PORT_CONNECT] = REG_FIELD(ISP176x_HC_PORTSC1, 0, 0),
++ [ALL_ATX_RESET] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 31, 31),
++ [HW_ANA_DIGI_OC] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 15, 15),
++ [HW_COMN_IRQ] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 10, 10),
++ [HW_DATA_BUS_WIDTH] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 8, 8),
++ [HW_DACK_POL_HIGH] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 6, 6),
++ [HW_DREQ_POL_HIGH] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 5, 5),
++ [HW_INTR_HIGH_ACT] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 2, 2),
++ [HW_INTR_EDGE_TRIG] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 1, 1),
++ [HW_GLOBAL_INTR_EN] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 0, 0),
++ [SW_RESET_RESET_ALL] = REG_FIELD(ISP176x_HC_RESET, 0, 0),
++ [INT_BUF_FILL] = REG_FIELD(ISP176x_HC_BUFFER_STATUS, 1, 1),
++ [ATL_BUF_FILL] = REG_FIELD(ISP176x_HC_BUFFER_STATUS, 0, 0),
++ [MEM_BANK_SEL] = REG_FIELD(ISP176x_HC_MEMORY, 16, 17),
++ [MEM_START_ADDR] = REG_FIELD(ISP176x_HC_MEMORY, 0, 15),
++ [HC_INT_ENABLE] = REG_FIELD(ISP176x_HC_INTERRUPT_ENABLE, 7, 8),
++};
+
+ /* -----------------------------------------------------------------------------
+ * Peripheral Controller
+ */
+
+-/* Initialization Registers */
+-#define DC_ADDRESS 0x0200
+-#define DC_DEVEN (1 << 7)
+-
+-#define DC_MODE 0x020c
+-#define DC_DMACLKON (1 << 9)
+-#define DC_VBUSSTAT (1 << 8)
+-#define DC_CLKAON (1 << 7)
+-#define DC_SNDRSU (1 << 6)
+-#define DC_GOSUSP (1 << 5)
+-#define DC_SFRESET (1 << 4)
+-#define DC_GLINTENA (1 << 3)
+-#define DC_WKUPCS (1 << 2)
+-
+-#define DC_INTCONF 0x0210
+-#define DC_CDBGMOD_ACK_NAK (0 << 6)
+-#define DC_CDBGMOD_ACK (1 << 6)
+-#define DC_CDBGMOD_ACK_1NAK (2 << 6)
+-#define DC_DDBGMODIN_ACK_NAK (0 << 4)
+-#define DC_DDBGMODIN_ACK (1 << 4)
+-#define DC_DDBGMODIN_ACK_1NAK (2 << 4)
+-#define DC_DDBGMODOUT_ACK_NYET_NAK (0 << 2)
+-#define DC_DDBGMODOUT_ACK_NYET (1 << 2)
+-#define DC_DDBGMODOUT_ACK_NYET_1NAK (2 << 2)
+-#define DC_INTLVL (1 << 1)
+-#define DC_INTPOL (1 << 0)
+-
+-#define DC_DEBUG 0x0212
+-#define DC_INTENABLE 0x0214
+ #define DC_IEPTX(n) (1 << (11 + 2 * (n)))
+ #define DC_IEPRX(n) (1 << (10 + 2 * (n)))
+ #define DC_IEPRXTX(n) (3 << (10 + 2 * (n)))
+-#define DC_IEP0SETUP (1 << 8)
+-#define DC_IEVBUS (1 << 7)
+-#define DC_IEDMA (1 << 6)
+-#define DC_IEHS_STA (1 << 5)
+-#define DC_IERESM (1 << 4)
+-#define DC_IESUSP (1 << 3)
+-#define DC_IEPSOF (1 << 2)
+-#define DC_IESOF (1 << 1)
+-#define DC_IEBRST (1 << 0)
++
++#define ISP176x_DC_ENDPTYP_ISOC 0x01
++#define ISP176x_DC_ENDPTYP_BULK 0x02
++#define ISP176x_DC_ENDPTYP_INTERRUPT 0x03
++
++/* Initialization Registers */
++#define ISP176x_DC_ADDRESS 0x0200
++#define ISP176x_DC_MODE 0x020c
++#define ISP176x_DC_INTCONF 0x0210
++#define ISP176x_DC_DEBUG 0x0212
++#define ISP176x_DC_INTENABLE 0x0214
+
+ /* Data Flow Registers */
+-#define DC_EPINDEX 0x022c
+-#define DC_EP0SETUP (1 << 5)
+-#define DC_ENDPIDX(n) ((n) << 1)
+-#define DC_EPDIR (1 << 0)
+-
+-#define DC_CTRLFUNC 0x0228
+-#define DC_CLBUF (1 << 4)
+-#define DC_VENDP (1 << 3)
+-#define DC_DSEN (1 << 2)
+-#define DC_STATUS (1 << 1)
+-#define DC_STALL (1 << 0)
+-
+-#define DC_DATAPORT 0x0220
+-#define DC_BUFLEN 0x021c
+-#define DC_DATACOUNT_MASK 0xffff
+-#define DC_BUFSTAT 0x021e
+-#define DC_EPMAXPKTSZ 0x0204
+-
+-#define DC_EPTYPE 0x0208
+-#define DC_NOEMPKT (1 << 4)
+-#define DC_EPENABLE (1 << 3)
+-#define DC_DBLBUF (1 << 2)
+-#define DC_ENDPTYP_ISOC (1 << 0)
+-#define DC_ENDPTYP_BULK (2 << 0)
+-#define DC_ENDPTYP_INTERRUPT (3 << 0)
++#define ISP176x_DC_EPMAXPKTSZ 0x0204
++#define ISP176x_DC_EPTYPE 0x0208
++
++#define ISP176x_DC_BUFLEN 0x021c
++#define ISP176x_DC_BUFSTAT 0x021e
++#define ISP176x_DC_DATAPORT 0x0220
++
++#define ISP176x_DC_CTRLFUNC 0x0228
++#define ISP176x_DC_EPINDEX 0x022c
++
++#define ISP1761_DC_OTG_CTRL_SET 0x374
++#define ISP1761_DC_OTG_CTRL_CLEAR 0x376
+
+ /* DMA Registers */
+-#define DC_DMACMD 0x0230
+-#define DC_DMATXCOUNT 0x0234
+-#define DC_DMACONF 0x0238
+-#define DC_DMAHW 0x023c
+-#define DC_DMAINTREASON 0x0250
+-#define DC_DMAINTEN 0x0254
+-#define DC_DMAEP 0x0258
+-#define DC_DMABURSTCOUNT 0x0264
++#define ISP176x_DC_DMACMD 0x0230
++#define ISP176x_DC_DMATXCOUNT 0x0234
++#define ISP176x_DC_DMACONF 0x0238
++#define ISP176x_DC_DMAHW 0x023c
++#define ISP176x_DC_DMAINTREASON 0x0250
++#define ISP176x_DC_DMAINTEN 0x0254
++#define ISP176x_DC_DMAEP 0x0258
++#define ISP176x_DC_DMABURSTCOUNT 0x0264
+
+ /* General Registers */
+-#define DC_INTERRUPT 0x0218
+-#define DC_CHIPID 0x0270
+-#define DC_FRAMENUM 0x0274
+-#define DC_SCRATCH 0x0278
+-#define DC_UNLOCKDEV 0x027c
+-#define DC_INTPULSEWIDTH 0x0280
+-#define DC_TESTMODE 0x0284
++#define ISP176x_DC_INTERRUPT 0x0218
++#define ISP176x_DC_CHIPID 0x0270
++#define ISP176x_DC_FRAMENUM 0x0274
++#define ISP176x_DC_SCRATCH 0x0278
++#define ISP176x_DC_UNLOCKDEV 0x027c
++#define ISP176x_DC_INTPULSEWIDTH 0x0280
++#define ISP176x_DC_TESTMODE 0x0284
++
++static const struct regmap_range isp176x_dc_volatile_ranges[] = {
++ regmap_reg_range(ISP176x_DC_EPMAXPKTSZ, ISP176x_DC_EPTYPE),
++ regmap_reg_range(ISP176x_DC_BUFLEN, ISP176x_DC_EPINDEX),
++ regmap_reg_range(ISP1761_DC_OTG_CTRL_SET, ISP1761_DC_OTG_CTRL_CLEAR),
++};
++
++static const struct regmap_access_table isp176x_dc_volatile_table = {
++ .yes_ranges = isp176x_dc_volatile_ranges,
++ .n_yes_ranges = ARRAY_SIZE(isp176x_dc_volatile_ranges),
++};
++
++enum isp176x_device_controller_fields {
++ /* DC_ADDRESS */
++ DC_DEVEN, DC_DEVADDR,
++ /* DC_MODE */
++ DC_VBUSSTAT, DC_SFRESET, DC_GLINTENA,
++ /* DC_INTCONF */
++ DC_CDBGMOD_ACK, DC_DDBGMODIN_ACK, DC_DDBGMODOUT_ACK, DC_INTPOL,
++ /* DC_INTENABLE */
++ DC_IEPRXTX_7, DC_IEPRXTX_6, DC_IEPRXTX_5, DC_IEPRXTX_4, DC_IEPRXTX_3,
++ DC_IEPRXTX_2, DC_IEPRXTX_1, DC_IEPRXTX_0,
++ DC_IEP0SETUP, DC_IEVBUS, DC_IEHS_STA, DC_IERESM, DC_IESUSP, DC_IEBRST,
++ /* DC_EPINDEX */
++ DC_EP0SETUP, DC_ENDPIDX, DC_EPDIR,
++ /* DC_CTRLFUNC */
++ DC_CLBUF, DC_VENDP, DC_DSEN, DC_STATUS, DC_STALL,
++ /* DC_BUFLEN */
++ DC_BUFLEN,
++ /* DC_EPMAXPKTSZ */
++ DC_FFOSZ,
++ /* DC_EPTYPE */
++ DC_EPENABLE, DC_ENDPTYP,
++ /* DC_FRAMENUM */
++ DC_FRAMENUM, DC_UFRAMENUM,
++ /* HW_OTG_CTRL_SET */
++ HW_OTG_DISABLE, HW_SW_SEL_HC_DC, HW_VBUS_DRV, HW_SEL_CP_EXT,
++ HW_DM_PULLDOWN, HW_DP_PULLDOWN, HW_DP_PULLUP,
++ /* HW_OTG_CTRL_CLR */
++ HW_OTG_DISABLE_CLEAR, HW_SW_SEL_HC_DC_CLEAR, HW_VBUS_DRV_CLEAR,
++ HW_SEL_CP_EXT_CLEAR, HW_DM_PULLDOWN_CLEAR, HW_DP_PULLDOWN_CLEAR,
++ HW_DP_PULLUP_CLEAR,
++ /* Last element */
++ DC_FIELD_MAX,
++};
++
++static const struct reg_field isp1761_dc_reg_fields[] = {
++ [DC_DEVEN] = REG_FIELD(ISP176x_DC_ADDRESS, 7, 7),
++ [DC_DEVADDR] = REG_FIELD(ISP176x_DC_ADDRESS, 0, 6),
++ [DC_VBUSSTAT] = REG_FIELD(ISP176x_DC_MODE, 8, 8),
++ [DC_SFRESET] = REG_FIELD(ISP176x_DC_MODE, 4, 4),
++ [DC_GLINTENA] = REG_FIELD(ISP176x_DC_MODE, 3, 3),
++ [DC_CDBGMOD_ACK] = REG_FIELD(ISP176x_DC_INTCONF, 6, 6),
++ [DC_DDBGMODIN_ACK] = REG_FIELD(ISP176x_DC_INTCONF, 4, 4),
++ [DC_DDBGMODOUT_ACK] = REG_FIELD(ISP176x_DC_INTCONF, 2, 2),
++ [DC_INTPOL] = REG_FIELD(ISP176x_DC_INTCONF, 0, 0),
++ [DC_IEPRXTX_7] = REG_FIELD(ISP176x_DC_INTENABLE, 25, 25),
++ [DC_IEPRXTX_6] = REG_FIELD(ISP176x_DC_INTENABLE, 23, 23),
++ [DC_IEPRXTX_5] = REG_FIELD(ISP176x_DC_INTENABLE, 21, 21),
++ [DC_IEPRXTX_4] = REG_FIELD(ISP176x_DC_INTENABLE, 19, 19),
++ [DC_IEPRXTX_3] = REG_FIELD(ISP176x_DC_INTENABLE, 17, 17),
++ [DC_IEPRXTX_2] = REG_FIELD(ISP176x_DC_INTENABLE, 15, 15),
++ [DC_IEPRXTX_1] = REG_FIELD(ISP176x_DC_INTENABLE, 13, 13),
++ [DC_IEPRXTX_0] = REG_FIELD(ISP176x_DC_INTENABLE, 11, 11),
++ [DC_IEP0SETUP] = REG_FIELD(ISP176x_DC_INTENABLE, 8, 8),
++ [DC_IEVBUS] = REG_FIELD(ISP176x_DC_INTENABLE, 7, 7),
++ [DC_IEHS_STA] = REG_FIELD(ISP176x_DC_INTENABLE, 5, 5),
++ [DC_IERESM] = REG_FIELD(ISP176x_DC_INTENABLE, 4, 4),
++ [DC_IESUSP] = REG_FIELD(ISP176x_DC_INTENABLE, 3, 3),
++ [DC_IEBRST] = REG_FIELD(ISP176x_DC_INTENABLE, 0, 0),
++ [DC_EP0SETUP] = REG_FIELD(ISP176x_DC_EPINDEX, 5, 5),
++ [DC_ENDPIDX] = REG_FIELD(ISP176x_DC_EPINDEX, 1, 4),
++ [DC_EPDIR] = REG_FIELD(ISP176x_DC_EPINDEX, 0, 0),
++ [DC_CLBUF] = REG_FIELD(ISP176x_DC_CTRLFUNC, 4, 4),
++ [DC_VENDP] = REG_FIELD(ISP176x_DC_CTRLFUNC, 3, 3),
++ [DC_DSEN] = REG_FIELD(ISP176x_DC_CTRLFUNC, 2, 2),
++ [DC_STATUS] = REG_FIELD(ISP176x_DC_CTRLFUNC, 1, 1),
++ [DC_STALL] = REG_FIELD(ISP176x_DC_CTRLFUNC, 0, 0),
++ [DC_BUFLEN] = REG_FIELD(ISP176x_DC_BUFLEN, 0, 15),
++ [DC_FFOSZ] = REG_FIELD(ISP176x_DC_EPMAXPKTSZ, 0, 10),
++ [DC_EPENABLE] = REG_FIELD(ISP176x_DC_EPTYPE, 3, 3),
++ [DC_ENDPTYP] = REG_FIELD(ISP176x_DC_EPTYPE, 0, 1),
++ [DC_UFRAMENUM] = REG_FIELD(ISP176x_DC_FRAMENUM, 11, 13),
++ [DC_FRAMENUM] = REG_FIELD(ISP176x_DC_FRAMENUM, 0, 10),
++ [HW_OTG_DISABLE] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 10, 10),
++ [HW_SW_SEL_HC_DC] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 7, 7),
++ [HW_VBUS_DRV] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 4, 4),
++ [HW_SEL_CP_EXT] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 3, 3),
++ [HW_DM_PULLDOWN] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 2, 2),
++ [HW_DP_PULLDOWN] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 1, 1),
++ [HW_DP_PULLUP] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 0, 0),
++ [HW_OTG_DISABLE] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 10, 10),
++ [HW_SW_SEL_HC_DC] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 7, 7),
++ [HW_VBUS_DRV] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 4, 4),
++ [HW_SEL_CP_EXT] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 3, 3),
++ [HW_DM_PULLDOWN] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 2, 2),
++ [HW_DP_PULLDOWN] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 1, 1),
++ [HW_DP_PULLUP] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 0, 0),
++};
+
+ #endif
+diff --git a/drivers/usb/isp1760/isp1760-udc.c b/drivers/usb/isp1760/isp1760-udc.c
+index 1714b2258b54..1ce21ef291b6 100644
+--- a/drivers/usb/isp1760/isp1760-udc.c
++++ b/drivers/usb/isp1760/isp1760-udc.c
+@@ -45,16 +45,62 @@ static inline struct isp1760_request *req_to_udc_req(struct usb_request *req)
+ return container_of(req, struct isp1760_request, req);
+ }
+
+-static inline u32 isp1760_udc_read(struct isp1760_udc *udc, u16 reg)
++static u32 isp1760_udc_read(struct isp1760_udc *udc, u16 field)
+ {
+- return isp1760_read32(udc->regs, reg);
++ return isp1760_field_read(udc->fields, field);
+ }
+
+-static inline void isp1760_udc_write(struct isp1760_udc *udc, u16 reg, u32 val)
++static void isp1760_udc_write(struct isp1760_udc *udc, u16 field, u32 val)
+ {
+- isp1760_write32(udc->regs, reg, val);
++ isp1760_field_write(udc->fields, field, val);
+ }
+
++static u32 isp1760_udc_read_raw(struct isp1760_udc *udc, u16 reg)
++{
++ u32 val;
++
++ regmap_raw_read(udc->regs, reg, &val, 4);
++
++ return le32_to_cpu(val);
++}
++
++static u16 isp1760_udc_read_raw16(struct isp1760_udc *udc, u16 reg)
++{
++ u16 val;
++
++ regmap_raw_read(udc->regs, reg, &val, 2);
++
++ return le16_to_cpu(val);
++}
++
++static void isp1760_udc_write_raw(struct isp1760_udc *udc, u16 reg, u32 val)
++{
++ val = cpu_to_le32(val);
++
++ regmap_raw_write(udc->regs, reg, &val, 4);
++}
++
++static void isp1760_udc_write_raw16(struct isp1760_udc *udc, u16 reg, u16 val)
++{
++ val = cpu_to_le16(val);
++
++ regmap_raw_write(udc->regs, reg, &val, 2);
++}
++
++static void isp1760_udc_set(struct isp1760_udc *udc, u32 field)
++{
++ isp1760_udc_write(udc, field, 0xFFFFFFFF);
++}
++
++static void isp1760_udc_clear(struct isp1760_udc *udc, u32 field)
++{
++ isp1760_udc_write(udc, field, 0);
++}
++
++static bool isp1760_udc_is_set(struct isp1760_udc *udc, u32 field)
++{
++ return !!isp1760_udc_read(udc, field);
++}
+ /* -----------------------------------------------------------------------------
+ * Endpoint Management
+ */
+@@ -75,11 +121,15 @@ static struct isp1760_ep *isp1760_udc_find_ep(struct isp1760_udc *udc,
+ return NULL;
+ }
+
+-static void __isp1760_udc_select_ep(struct isp1760_ep *ep, int dir)
++static void __isp1760_udc_select_ep(struct isp1760_udc *udc,
++ struct isp1760_ep *ep, int dir)
+ {
+- isp1760_udc_write(ep->udc, DC_EPINDEX,
+- DC_ENDPIDX(ep->addr & USB_ENDPOINT_NUMBER_MASK) |
+- (dir == USB_DIR_IN ? DC_EPDIR : 0));
++ isp1760_udc_write(udc, DC_ENDPIDX, ep->addr & USB_ENDPOINT_NUMBER_MASK);
++
++ if (dir == USB_DIR_IN)
++ isp1760_udc_set(udc, DC_EPDIR);
++ else
++ isp1760_udc_clear(udc, DC_EPDIR);
+ }
+
+ /**
+@@ -93,9 +143,10 @@ static void __isp1760_udc_select_ep(struct isp1760_ep *ep, int dir)
+ *
+ * Called with the UDC spinlock held.
+ */
+-static void isp1760_udc_select_ep(struct isp1760_ep *ep)
++static void isp1760_udc_select_ep(struct isp1760_udc *udc,
++ struct isp1760_ep *ep)
+ {
+- __isp1760_udc_select_ep(ep, ep->addr & USB_ENDPOINT_DIR_MASK);
++ __isp1760_udc_select_ep(udc, ep, ep->addr & USB_ENDPOINT_DIR_MASK);
+ }
+
+ /* Called with the UDC spinlock held. */
+@@ -108,9 +159,13 @@ static void isp1760_udc_ctrl_send_status(struct isp1760_ep *ep, int dir)
+ * the direction opposite to the data stage data packets, we thus need
+ * to select the OUT/IN endpoint for IN/OUT transfers.
+ */
+- isp1760_udc_write(udc, DC_EPINDEX, DC_ENDPIDX(0) |
+- (dir == USB_DIR_IN ? 0 : DC_EPDIR));
+- isp1760_udc_write(udc, DC_CTRLFUNC, DC_STATUS);
++ if (dir == USB_DIR_IN)
++ isp1760_udc_clear(udc, DC_EPDIR);
++ else
++ isp1760_udc_set(udc, DC_EPDIR);
++
++ isp1760_udc_write(udc, DC_ENDPIDX, 1);
++ isp1760_udc_set(udc, DC_STATUS);
+
+ /*
+ * The hardware will terminate the request automatically and go back to
+@@ -157,10 +212,10 @@ static void isp1760_udc_ctrl_send_stall(struct isp1760_ep *ep)
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* Stall both the IN and OUT endpoints. */
+- __isp1760_udc_select_ep(ep, USB_DIR_OUT);
+- isp1760_udc_write(udc, DC_CTRLFUNC, DC_STALL);
+- __isp1760_udc_select_ep(ep, USB_DIR_IN);
+- isp1760_udc_write(udc, DC_CTRLFUNC, DC_STALL);
++ __isp1760_udc_select_ep(udc, ep, USB_DIR_OUT);
++ isp1760_udc_set(udc, DC_STALL);
++ __isp1760_udc_select_ep(udc, ep, USB_DIR_IN);
++ isp1760_udc_set(udc, DC_STALL);
+
+ /* A protocol stall completes the control transaction. */
+ udc->ep0_state = ISP1760_CTRL_SETUP;
+@@ -181,8 +236,8 @@ static bool isp1760_udc_receive(struct isp1760_ep *ep,
+ u32 *buf;
+ int i;
+
+- isp1760_udc_select_ep(ep);
+- len = isp1760_udc_read(udc, DC_BUFLEN) & DC_DATACOUNT_MASK;
++ isp1760_udc_select_ep(udc, ep);
++ len = isp1760_udc_read(udc, DC_BUFLEN);
+
+ dev_dbg(udc->isp->dev, "%s: received %u bytes (%u/%u done)\n",
+ __func__, len, req->req.actual, req->req.length);
+@@ -198,7 +253,7 @@ static bool isp1760_udc_receive(struct isp1760_ep *ep,
+ * datasheet doesn't clearly document how this should be
+ * handled.
+ */
+- isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF);
++ isp1760_udc_set(udc, DC_CLBUF);
+ return false;
+ }
+
+@@ -209,9 +264,9 @@ static bool isp1760_udc_receive(struct isp1760_ep *ep,
+ * the next packet might be removed from the FIFO.
+ */
+ for (i = len; i > 2; i -= 4, ++buf)
+- *buf = le32_to_cpu(isp1760_udc_read(udc, DC_DATAPORT));
++ *buf = isp1760_udc_read_raw(udc, ISP176x_DC_DATAPORT);
+ if (i > 0)
+- *(u16 *)buf = le16_to_cpu(readw(udc->regs + DC_DATAPORT));
++ *(u16 *)buf = isp1760_udc_read_raw16(udc, ISP176x_DC_DATAPORT);
+
+ req->req.actual += len;
+
+@@ -253,7 +308,7 @@ static void isp1760_udc_transmit(struct isp1760_ep *ep,
+ __func__, req->packet_size, req->req.actual,
+ req->req.length);
+
+- __isp1760_udc_select_ep(ep, USB_DIR_IN);
++ __isp1760_udc_select_ep(udc, ep, USB_DIR_IN);
+
+ if (req->packet_size)
+ isp1760_udc_write(udc, DC_BUFLEN, req->packet_size);
+@@ -265,14 +320,14 @@ static void isp1760_udc_transmit(struct isp1760_ep *ep,
+ * the FIFO for this kind of conditions, but doesn't seem to work.
+ */
+ for (i = req->packet_size; i > 2; i -= 4, ++buf)
+- isp1760_udc_write(udc, DC_DATAPORT, cpu_to_le32(*buf));
++ isp1760_udc_write_raw(udc, ISP176x_DC_DATAPORT, *buf);
+ if (i > 0)
+- writew(cpu_to_le16(*(u16 *)buf), udc->regs + DC_DATAPORT);
++ isp1760_udc_write_raw16(udc, ISP176x_DC_DATAPORT, *(u16 *)buf);
+
+ if (ep->addr == 0)
+- isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN);
++ isp1760_udc_set(udc, DC_DSEN);
+ if (!req->packet_size)
+- isp1760_udc_write(udc, DC_CTRLFUNC, DC_VENDP);
++ isp1760_udc_set(udc, DC_VENDP);
+ }
+
+ static void isp1760_ep_rx_ready(struct isp1760_ep *ep)
+@@ -408,19 +463,24 @@ static int __isp1760_udc_set_halt(struct isp1760_ep *ep, bool halt)
+ return -EINVAL;
+ }
+
+- isp1760_udc_select_ep(ep);
+- isp1760_udc_write(udc, DC_CTRLFUNC, halt ? DC_STALL : 0);
++ isp1760_udc_select_ep(udc, ep);
++
++ if (halt)
++ isp1760_udc_set(udc, DC_STALL);
++ else
++ isp1760_udc_clear(udc, DC_STALL);
+
+ if (ep->addr == 0) {
+ /* When halting the control endpoint, stall both IN and OUT. */
+- __isp1760_udc_select_ep(ep, USB_DIR_IN);
+- isp1760_udc_write(udc, DC_CTRLFUNC, halt ? DC_STALL : 0);
++ __isp1760_udc_select_ep(udc, ep, USB_DIR_IN);
++ if (halt)
++ isp1760_udc_set(udc, DC_STALL);
++ else
++ isp1760_udc_clear(udc, DC_STALL);
+ } else if (!halt) {
+ /* Reset the data PID by cycling the endpoint enable bit. */
+- u16 eptype = isp1760_udc_read(udc, DC_EPTYPE);
+-
+- isp1760_udc_write(udc, DC_EPTYPE, eptype & ~DC_EPENABLE);
+- isp1760_udc_write(udc, DC_EPTYPE, eptype);
++ isp1760_udc_clear(udc, DC_EPENABLE);
++ isp1760_udc_set(udc, DC_EPENABLE);
+
+ /*
+ * Disabling the endpoint emptied the transmit FIFO, fill it
+@@ -479,12 +539,14 @@ static int isp1760_udc_get_status(struct isp1760_udc *udc,
+ return -EINVAL;
+ }
+
+- isp1760_udc_write(udc, DC_EPINDEX, DC_ENDPIDX(0) | DC_EPDIR);
++ isp1760_udc_set(udc, DC_EPDIR);
++ isp1760_udc_write(udc, DC_ENDPIDX, 1);
++
+ isp1760_udc_write(udc, DC_BUFLEN, 2);
+
+- writew(cpu_to_le16(status), udc->regs + DC_DATAPORT);
++ isp1760_udc_write_raw16(udc, ISP176x_DC_DATAPORT, status);
+
+- isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN);
++ isp1760_udc_set(udc, DC_DSEN);
+
+ dev_dbg(udc->isp->dev, "%s: status 0x%04x\n", __func__, status);
+
+@@ -508,7 +570,8 @@ static int isp1760_udc_set_address(struct isp1760_udc *udc, u16 addr)
+ usb_gadget_set_state(&udc->gadget, addr ? USB_STATE_ADDRESS :
+ USB_STATE_DEFAULT);
+
+- isp1760_udc_write(udc, DC_ADDRESS, DC_DEVEN | addr);
++ isp1760_udc_write(udc, DC_DEVADDR, addr);
++ isp1760_udc_set(udc, DC_DEVEN);
+
+ spin_lock(&udc->lock);
+ isp1760_udc_ctrl_send_status(&udc->ep[0], USB_DIR_OUT);
+@@ -650,9 +713,9 @@ static void isp1760_ep0_setup(struct isp1760_udc *udc)
+
+ spin_lock(&udc->lock);
+
+- isp1760_udc_write(udc, DC_EPINDEX, DC_EP0SETUP);
++ isp1760_udc_set(udc, DC_EP0SETUP);
+
+- count = isp1760_udc_read(udc, DC_BUFLEN) & DC_DATACOUNT_MASK;
++ count = isp1760_udc_read(udc, DC_BUFLEN);
+ if (count != sizeof(req)) {
+ spin_unlock(&udc->lock);
+
+@@ -663,8 +726,8 @@ static void isp1760_ep0_setup(struct isp1760_udc *udc)
+ return;
+ }
+
+- req.data[0] = isp1760_udc_read(udc, DC_DATAPORT);
+- req.data[1] = isp1760_udc_read(udc, DC_DATAPORT);
++ req.data[0] = isp1760_udc_read_raw(udc, ISP176x_DC_DATAPORT);
++ req.data[1] = isp1760_udc_read_raw(udc, ISP176x_DC_DATAPORT);
+
+ if (udc->ep0_state != ISP1760_CTRL_SETUP) {
+ spin_unlock(&udc->lock);
+@@ -732,13 +795,13 @@ static int isp1760_ep_enable(struct usb_ep *ep,
+
+ switch (usb_endpoint_type(desc)) {
+ case USB_ENDPOINT_XFER_ISOC:
+- type = DC_ENDPTYP_ISOC;
++ type = ISP176x_DC_ENDPTYP_ISOC;
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+- type = DC_ENDPTYP_BULK;
++ type = ISP176x_DC_ENDPTYP_BULK;
+ break;
+ case USB_ENDPOINT_XFER_INT:
+- type = DC_ENDPTYP_INTERRUPT;
++ type = ISP176x_DC_ENDPTYP_INTERRUPT;
+ break;
+ case USB_ENDPOINT_XFER_CONTROL:
+ default:
+@@ -755,10 +818,13 @@ static int isp1760_ep_enable(struct usb_ep *ep,
+ uep->halted = false;
+ uep->wedged = false;
+
+- isp1760_udc_select_ep(uep);
+- isp1760_udc_write(udc, DC_EPMAXPKTSZ, uep->maxpacket);
++ isp1760_udc_select_ep(udc, uep);
++
++ isp1760_udc_write(udc, DC_FFOSZ, uep->maxpacket);
+ isp1760_udc_write(udc, DC_BUFLEN, uep->maxpacket);
+- isp1760_udc_write(udc, DC_EPTYPE, DC_EPENABLE | type);
++
++ isp1760_udc_write(udc, DC_ENDPTYP, type);
++ isp1760_udc_set(udc, DC_EPENABLE);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+@@ -786,8 +852,9 @@ static int isp1760_ep_disable(struct usb_ep *ep)
+ uep->desc = NULL;
+ uep->maxpacket = 0;
+
+- isp1760_udc_select_ep(uep);
+- isp1760_udc_write(udc, DC_EPTYPE, 0);
++ isp1760_udc_select_ep(udc, uep);
++ isp1760_udc_clear(udc, DC_EPENABLE);
++ isp1760_udc_clear(udc, DC_ENDPTYP);
+
+ /* TODO Synchronize with the IRQ handler */
+
+@@ -864,8 +931,8 @@ static int isp1760_ep_queue(struct usb_ep *ep, struct usb_request *_req,
+
+ case ISP1760_CTRL_DATA_OUT:
+ list_add_tail(&req->queue, &uep->queue);
+- __isp1760_udc_select_ep(uep, USB_DIR_OUT);
+- isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN);
++ __isp1760_udc_select_ep(udc, uep, USB_DIR_OUT);
++ isp1760_udc_set(udc, DC_DSEN);
+ break;
+
+ case ISP1760_CTRL_STATUS:
+@@ -1025,14 +1092,14 @@ static void isp1760_ep_fifo_flush(struct usb_ep *ep)
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+- isp1760_udc_select_ep(uep);
++ isp1760_udc_select_ep(udc, uep);
+
+ /*
+ * Set the CLBUF bit twice to flush both buffers in case double
+ * buffering is enabled.
+ */
+- isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF);
+- isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF);
++ isp1760_udc_set(udc, DC_CLBUF);
++ isp1760_udc_set(udc, DC_CLBUF);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+ }
+@@ -1091,19 +1158,30 @@ static void isp1760_udc_init_hw(struct isp1760_udc *udc)
+ * ACK tokens only (and NYET for the out pipe). The default
+ * configuration also generates an interrupt on the first NACK token.
+ */
+- isp1760_udc_write(udc, DC_INTCONF, DC_CDBGMOD_ACK | DC_DDBGMODIN_ACK |
+- DC_DDBGMODOUT_ACK_NYET);
+-
+- isp1760_udc_write(udc, DC_INTENABLE, DC_IEPRXTX(7) | DC_IEPRXTX(6) |
+- DC_IEPRXTX(5) | DC_IEPRXTX(4) | DC_IEPRXTX(3) |
+- DC_IEPRXTX(2) | DC_IEPRXTX(1) | DC_IEPRXTX(0) |
+- DC_IEP0SETUP | DC_IEVBUS | DC_IERESM | DC_IESUSP |
+- DC_IEHS_STA | DC_IEBRST);
++ isp1760_udc_set(udc, DC_CDBGMOD_ACK);
++ isp1760_udc_set(udc, DC_DDBGMODIN_ACK);
++ isp1760_udc_set(udc, DC_DDBGMODOUT_ACK);
++
++ isp1760_udc_set(udc, DC_IEPRXTX_7);
++ isp1760_udc_set(udc, DC_IEPRXTX_6);
++ isp1760_udc_set(udc, DC_IEPRXTX_5);
++ isp1760_udc_set(udc, DC_IEPRXTX_4);
++ isp1760_udc_set(udc, DC_IEPRXTX_3);
++ isp1760_udc_set(udc, DC_IEPRXTX_2);
++ isp1760_udc_set(udc, DC_IEPRXTX_1);
++ isp1760_udc_set(udc, DC_IEPRXTX_0);
++
++ isp1760_udc_set(udc, DC_IEP0SETUP);
++ isp1760_udc_set(udc, DC_IEVBUS);
++ isp1760_udc_set(udc, DC_IERESM);
++ isp1760_udc_set(udc, DC_IESUSP);
++ isp1760_udc_set(udc, DC_IEHS_STA);
++ isp1760_udc_set(udc, DC_IEBRST);
+
+ if (udc->connected)
+ isp1760_set_pullup(udc->isp, true);
+
+- isp1760_udc_write(udc, DC_ADDRESS, DC_DEVEN);
++ isp1760_udc_set(udc, DC_DEVEN);
+ }
+
+ static void isp1760_udc_reset(struct isp1760_udc *udc)
+@@ -1152,7 +1230,7 @@ static int isp1760_udc_get_frame(struct usb_gadget *gadget)
+ {
+ struct isp1760_udc *udc = gadget_to_udc(gadget);
+
+- return isp1760_udc_read(udc, DC_FRAMENUM) & ((1 << 11) - 1);
++ return isp1760_udc_read(udc, DC_FRAMENUM);
+ }
+
+ static int isp1760_udc_wakeup(struct usb_gadget *gadget)
+@@ -1219,7 +1297,7 @@ static int isp1760_udc_start(struct usb_gadget *gadget,
+ usb_gadget_set_state(&udc->gadget, USB_STATE_ATTACHED);
+
+ /* DMA isn't supported yet, don't enable the DMA clock. */
+- isp1760_udc_write(udc, DC_MODE, DC_GLINTENA);
++ isp1760_udc_set(udc, DC_GLINTENA);
+
+ isp1760_udc_init_hw(udc);
+
+@@ -1238,7 +1316,7 @@ static int isp1760_udc_stop(struct usb_gadget *gadget)
+
+ del_timer_sync(&udc->vbus_timer);
+
+- isp1760_udc_write(udc, DC_MODE, 0);
++ isp1760_reg_write(udc->regs, ISP176x_DC_MODE, 0);
+
+ spin_lock_irqsave(&udc->lock, flags);
+ udc->driver = NULL;
+@@ -1266,9 +1344,9 @@ static irqreturn_t isp1760_udc_irq(int irq, void *dev)
+ unsigned int i;
+ u32 status;
+
+- status = isp1760_udc_read(udc, DC_INTERRUPT)
+- & isp1760_udc_read(udc, DC_INTENABLE);
+- isp1760_udc_write(udc, DC_INTERRUPT, status);
++ status = isp1760_reg_read(udc->regs, ISP176x_DC_INTERRUPT)
++ & isp1760_reg_read(udc->regs, ISP176x_DC_INTENABLE);
++ isp1760_reg_write(udc->regs, ISP176x_DC_INTERRUPT, status);
+
+ if (status & DC_IEVBUS) {
+ dev_dbg(udc->isp->dev, "%s(VBUS)\n", __func__);
+@@ -1313,7 +1391,7 @@ static irqreturn_t isp1760_udc_irq(int irq, void *dev)
+ dev_dbg(udc->isp->dev, "%s(SUSP)\n", __func__);
+
+ spin_lock(&udc->lock);
+- if (!(isp1760_udc_read(udc, DC_MODE) & DC_VBUSSTAT))
++ if (!isp1760_udc_is_set(udc, DC_VBUSSTAT))
+ isp1760_udc_disconnect(udc);
+ else
+ isp1760_udc_suspend(udc);
+@@ -1335,7 +1413,7 @@ static void isp1760_udc_vbus_poll(struct timer_list *t)
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+- if (!(isp1760_udc_read(udc, DC_MODE) & DC_VBUSSTAT))
++ if (!(isp1760_udc_is_set(udc, DC_VBUSSTAT)))
+ isp1760_udc_disconnect(udc);
+ else if (udc->gadget.state >= USB_STATE_POWERED)
+ mod_timer(&udc->vbus_timer,
+@@ -1412,9 +1490,9 @@ static int isp1760_udc_init(struct isp1760_udc *udc)
+ * register, and reading the scratch register value back. The chip ID
+ * and scratch register contents must match the expected values.
+ */
+- isp1760_udc_write(udc, DC_SCRATCH, 0xbabe);
+- chipid = isp1760_udc_read(udc, DC_CHIPID);
+- scratch = isp1760_udc_read(udc, DC_SCRATCH);
++ isp1760_reg_write(udc->regs, ISP176x_DC_SCRATCH, 0xbabe);
++ chipid = isp1760_reg_read(udc->regs, ISP176x_DC_CHIPID);
++ scratch = isp1760_reg_read(udc->regs, ISP176x_DC_SCRATCH);
+
+ if (scratch != 0xbabe) {
+ dev_err(udc->isp->dev,
+@@ -1429,9 +1507,9 @@ static int isp1760_udc_init(struct isp1760_udc *udc)
+ }
+
+ /* Reset the device controller. */
+- isp1760_udc_write(udc, DC_MODE, DC_SFRESET);
++ isp1760_udc_set(udc, DC_SFRESET);
+ usleep_range(10000, 11000);
+- isp1760_udc_write(udc, DC_MODE, 0);
++ isp1760_reg_write(udc->regs, ISP176x_DC_MODE, 0);
+ usleep_range(10000, 11000);
+
+ return 0;
+@@ -1445,7 +1523,6 @@ int isp1760_udc_register(struct isp1760_device *isp, int irq,
+
+ udc->irq = -1;
+ udc->isp = isp;
+- udc->regs = isp->regs;
+
+ spin_lock_init(&udc->lock);
+ timer_setup(&udc->vbus_timer, isp1760_udc_vbus_poll, 0);
+diff --git a/drivers/usb/isp1760/isp1760-udc.h b/drivers/usb/isp1760/isp1760-udc.h
+index 2d0b88747701..12626bf2fe4d 100644
+--- a/drivers/usb/isp1760/isp1760-udc.h
++++ b/drivers/usb/isp1760/isp1760-udc.h
+@@ -17,6 +17,8 @@
+ #include <linux/timer.h>
+ #include <linux/usb/gadget.h>
+
++#include "isp1760-regs.h"
++
+ struct isp1760_device;
+ struct isp1760_udc;
+
+@@ -48,7 +50,7 @@ struct isp1760_ep {
+ * struct isp1760_udc - UDC state information
+ * irq: IRQ number
+ * irqname: IRQ name (as passed to request_irq)
+- * regs: Base address of the UDC registers
++ * regs: regmap for UDC registers
+ * driver: Gadget driver
+ * gadget: Gadget device
+ * lock: Protects driver, vbus_timer, ep, ep0_*, DC_EPINDEX register
+@@ -59,12 +61,13 @@ struct isp1760_ep {
+ * connected: Tracks gadget driver bus connection state
+ */
+ struct isp1760_udc {
+-#ifdef CONFIG_USB_ISP1761_UDC
+ struct isp1760_device *isp;
+
+ int irq;
+ char *irqname;
+- void __iomem *regs;
++
++ struct regmap *regs;
++ struct regmap_field *fields[DC_FIELD_MAX];
+
+ struct usb_gadget_driver *driver;
+ struct usb_gadget gadget;
+@@ -81,7 +84,6 @@ struct isp1760_udc {
+ bool connected;
+
+ unsigned int devstatus;
+-#endif
+ };
+
+ #ifdef CONFIG_USB_ISP1761_UDC
+--
+2.17.1
+
new file mode 100644
@@ -0,0 +1,302 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+
+From a2d7a69e994ea67583bbd766a85b2c89f35b45b5 Mon Sep 17 00:00:00 2001
+From: Rui Miguel Silva <rui.silva@linaro.org>
+Date: Fri, 26 Jun 2020 16:37:30 +0100
+Subject: [PATCH 19/20] usb: isp1760: hcd: refactor mempool config and setup
+
+In preparation to support other family member IP, which may have
+different memory layout. Drop macros and setup a configuration
+struct.
+
+Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
+---
+ drivers/usb/isp1760/isp1760-core.c | 21 ++++++++
+ drivers/usb/isp1760/isp1760-hcd.c | 83 ++++++++++++++++++++----------
+ drivers/usb/isp1760/isp1760-hcd.h | 37 ++++++-------
+ 3 files changed, 92 insertions(+), 49 deletions(-)
+
+diff --git a/drivers/usb/isp1760/isp1760-core.c b/drivers/usb/isp1760/isp1760-core.c
+index f7f680046a15..88f233c11397 100644
+--- a/drivers/usb/isp1760/isp1760-core.c
++++ b/drivers/usb/isp1760/isp1760-core.c
+@@ -102,6 +102,25 @@ void isp1760_set_pullup(struct isp1760_device *isp, bool enable)
+ isp1760_field_set(udc->fields, HW_DP_PULLUP_CLEAR);
+ }
+
++/*
++ * 60kb divided in:
++ * - 32 blocks @ 256 bytes
++ * - 20 blocks @ 1024 bytes
++ * - 4 blocks @ 8192 bytes
++ */
++static const struct isp1760_memory_layout isp176x_memory_conf = {
++ .blocks[0] = 32,
++ .blocks_size[0] = 256,
++ .blocks[1] = 20,
++ .blocks_size[1] = 1024,
++ .blocks[2] = 4,
++ .blocks_size[2] = 8192,
++
++ .ptd_num = 32,
++ .payload_blocks = 32 + 20 + 4,
++ .payload_area_size = 0xf000,
++};
++
+ static const struct regmap_config isp1760_hc_regmap_conf = {
+ .name = "isp1760-hc",
+ .reg_bits = 16,
+@@ -183,6 +202,8 @@ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
+ udc->fields[i] = f;
+ }
+
++ hcd->memory_layout = &isp176x_memory_conf;
++
+ isp1760_init_core(isp);
+
+ if (IS_ENABLED(CONFIG_USB_ISP1760_HCD) && !usb_disabled()) {
+diff --git a/drivers/usb/isp1760/isp1760-hcd.c b/drivers/usb/isp1760/isp1760-hcd.c
+index 76fed6e062ed..0f54a989dbed 100644
+--- a/drivers/usb/isp1760/isp1760-hcd.c
++++ b/drivers/usb/isp1760/isp1760-hcd.c
+@@ -354,39 +354,29 @@ static void ptd_write(void __iomem *base, u32 ptd_offset, u32 slot,
+ /* memory management of the 60kb on the chip from 0x1000 to 0xffff */
+ static void init_memory(struct isp1760_hcd *priv)
+ {
+- int i, curr;
++ const struct isp1760_memory_layout *mem = priv->memory_layout;
++ int i, j, curr;
+ u32 payload_addr;
+
+ payload_addr = PAYLOAD_OFFSET;
+- for (i = 0; i < BLOCK_1_NUM; i++) {
+- priv->memory_pool[i].start = payload_addr;
+- priv->memory_pool[i].size = BLOCK_1_SIZE;
+- priv->memory_pool[i].free = 1;
+- payload_addr += priv->memory_pool[i].size;
+- }
+-
+- curr = i;
+- for (i = 0; i < BLOCK_2_NUM; i++) {
+- priv->memory_pool[curr + i].start = payload_addr;
+- priv->memory_pool[curr + i].size = BLOCK_2_SIZE;
+- priv->memory_pool[curr + i].free = 1;
+- payload_addr += priv->memory_pool[curr + i].size;
+- }
+
+- curr = i;
+- for (i = 0; i < BLOCK_3_NUM; i++) {
+- priv->memory_pool[curr + i].start = payload_addr;
+- priv->memory_pool[curr + i].size = BLOCK_3_SIZE;
+- priv->memory_pool[curr + i].free = 1;
+- payload_addr += priv->memory_pool[curr + i].size;
++ for (i = 0, curr = 0; i < ARRAY_SIZE(mem->blocks); i++) {
++ for (j = 0; j < mem->blocks[i]; j++, curr++) {
++ priv->memory_pool[curr + j].start = payload_addr;
++ priv->memory_pool[curr + j].size = mem->blocks_size[i];
++ priv->memory_pool[curr + j].free = 1;
++ payload_addr += priv->memory_pool[curr + j].size;
++ }
+ }
+
+- WARN_ON(payload_addr - priv->memory_pool[0].start > PAYLOAD_AREA_SIZE);
++ WARN_ON(payload_addr - priv->memory_pool[0].start >
++ mem->payload_area_size);
+ }
+
+ static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
+ {
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++ const struct isp1760_memory_layout *mem = priv->memory_layout;
+ int i;
+
+ WARN_ON(qtd->payload_addr);
+@@ -394,7 +384,7 @@ static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
+ if (!qtd->length)
+ return;
+
+- for (i = 0; i < BLOCKS; i++) {
++ for (i = 0; i < mem->payload_blocks; i++) {
+ if (priv->memory_pool[i].size >= qtd->length &&
+ priv->memory_pool[i].free) {
+ priv->memory_pool[i].free = 0;
+@@ -407,12 +397,13 @@ static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
+ static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
+ {
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++ const struct isp1760_memory_layout *mem = priv->memory_layout;
+ int i;
+
+ if (!qtd->payload_addr)
+ return;
+
+- for (i = 0; i < BLOCKS; i++) {
++ for (i = 0; i < mem->payload_blocks; i++) {
+ if (priv->memory_pool[i].start == qtd->payload_addr) {
+ WARN_ON(priv->memory_pool[i].free);
+ priv->memory_pool[i].free = 1;
+@@ -1403,8 +1394,6 @@ static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len)
+ {
+ qtd->data_buffer = databuffer;
+
+- if (len > MAX_PAYLOAD_SIZE)
+- len = MAX_PAYLOAD_SIZE;
+ qtd->length = len;
+
+ return qtd->length;
+@@ -1428,6 +1417,8 @@ static void qtd_list_free(struct list_head *qtd_list)
+ static void packetize_urb(struct usb_hcd *hcd,
+ struct urb *urb, struct list_head *head, gfp_t flags)
+ {
++ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++ const struct isp1760_memory_layout *mem = priv->memory_layout;
+ struct isp1760_qtd *qtd;
+ void *buf;
+ int len, maxpacketsize;
+@@ -1480,6 +1471,10 @@ static void packetize_urb(struct usb_hcd *hcd,
+ qtd = qtd_alloc(flags, urb, packet_type);
+ if (!qtd)
+ goto cleanup;
++
++ if (len > mem->blocks_size[ISP176x_BLOCK_NUM - 1])
++ len = mem->blocks_size[ISP176x_BLOCK_NUM - 1];
++
+ this_qtd_len = qtd_fill(qtd, buf, len);
+ list_add_tail(&qtd->qtd_list, head);
+
+@@ -2209,6 +2204,7 @@ int isp1760_hcd_register(struct isp1760_hcd *priv, struct resource *mem,
+ int irq, unsigned long irqflags,
+ struct device *dev)
+ {
++ const struct isp1760_memory_layout *mem_layout = priv->memory_layout;
+ struct usb_hcd *hcd;
+ int ret;
+
+@@ -2220,6 +2216,28 @@ int isp1760_hcd_register(struct isp1760_hcd *priv, struct resource *mem,
+
+ priv->hcd = hcd;
+
++ priv->memory_pool = kcalloc(mem_layout->payload_blocks,
++ sizeof(struct isp1760_memory_chunk),
++ GFP_KERNEL);
++ if (!priv->memory_pool) {
++ ret = -ENOMEM;
++ goto put_hcd;
++ }
++
++ priv->atl_slots = kcalloc(mem_layout->ptd_num,
++ sizeof(struct isp1760_slotinfo), GFP_KERNEL);
++ if (!priv->atl_slots) {
++ ret = -ENOMEM;
++ goto free_mem_pool;
++ }
++
++ priv->int_slots = kcalloc(mem_layout->ptd_num,
++ sizeof(struct isp1760_slotinfo), GFP_KERNEL);
++ if (!priv->int_slots) {
++ ret = -ENOMEM;
++ goto free_atl_slots;
++ }
++
+ init_memory(priv);
+
+ hcd->irq = irq;
+@@ -2231,13 +2249,19 @@ int isp1760_hcd_register(struct isp1760_hcd *priv, struct resource *mem,
+
+ ret = usb_add_hcd(hcd, irq, irqflags);
+ if (ret)
+- goto error;
++ goto free_int_slots;
+
+ device_wakeup_enable(hcd->self.controller);
+
+ return 0;
+
+-error:
++free_int_slots:
++ kfree(priv->int_slots);
++free_atl_slots:
++ kfree(priv->atl_slots);
++free_mem_pool:
++ kfree(priv->memory_pool);
++put_hcd:
+ usb_put_hcd(hcd);
+ return ret;
+ }
+@@ -2249,4 +2273,7 @@ void isp1760_hcd_unregister(struct isp1760_hcd *priv)
+
+ usb_remove_hcd(priv->hcd);
+ usb_put_hcd(priv->hcd);
++ kfree(priv->atl_slots);
++ kfree(priv->int_slots);
++ kfree(priv->memory_pool);
+ }
+diff --git a/drivers/usb/isp1760/isp1760-hcd.h b/drivers/usb/isp1760/isp1760-hcd.h
+index 7a1f4f2607be..e5e784b9046b 100644
+--- a/drivers/usb/isp1760/isp1760-hcd.h
++++ b/drivers/usb/isp1760/isp1760-hcd.h
+@@ -12,24 +12,6 @@ struct isp1760_qtd;
+ struct resource;
+ struct usb_hcd;
+
+-/*
+- * 60kb divided in:
+- * - 32 blocks @ 256 bytes
+- * - 20 blocks @ 1024 bytes
+- * - 4 blocks @ 8192 bytes
+- */
+-
+-#define BLOCK_1_NUM 32
+-#define BLOCK_2_NUM 20
+-#define BLOCK_3_NUM 4
+-
+-#define BLOCK_1_SIZE 256
+-#define BLOCK_2_SIZE 1024
+-#define BLOCK_3_SIZE 8192
+-#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM)
+-#define MAX_PAYLOAD_SIZE BLOCK_3_SIZE
+-#define PAYLOAD_AREA_SIZE 0xf000
+-
+ struct isp1760_slotinfo {
+ struct isp1760_qh *qh;
+ struct isp1760_qtd *qtd;
+@@ -37,6 +19,17 @@ struct isp1760_slotinfo {
+ };
+
+ /* chip memory management */
++#define ISP176x_BLOCK_NUM 3
++
++struct isp1760_memory_layout {
++ unsigned int blocks[ISP176x_BLOCK_NUM];
++ unsigned int blocks_size[ISP176x_BLOCK_NUM];
++
++ unsigned int ptd_num;
++ unsigned int payload_blocks;
++ unsigned int payload_area_size;
++};
++
+ struct isp1760_memory_chunk {
+ unsigned int start;
+ unsigned int size;
+@@ -59,12 +52,14 @@ struct isp1760_hcd {
+ struct regmap *regs;
+ struct regmap_field *fields[HC_FIELD_MAX];
+
++ const struct isp1760_memory_layout *memory_layout;
++
+ spinlock_t lock;
+- struct isp1760_slotinfo atl_slots[32];
++ struct isp1760_slotinfo *atl_slots;
+ int atl_done_map;
+- struct isp1760_slotinfo int_slots[32];
++ struct isp1760_slotinfo *int_slots;
+ int int_done_map;
+- struct isp1760_memory_chunk memory_pool[BLOCKS];
++ struct isp1760_memory_chunk *memory_pool;
+ struct list_head qh_list[QH_END];
+
+ /* periodic schedule support */
+--
+2.17.1
+
new file mode 100644
@@ -0,0 +1,1755 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+
+From bc76719de2c28375274a5c529f36a405532106f0 Mon Sep 17 00:00:00 2001
+From: Rui Miguel Silva <rui.silva@linaro.org>
+Date: Wed, 15 Jul 2020 01:28:09 +0100
+Subject: [PATCH 20/20] usb: isp1760: add support for isp1763
+
+isp1763 have some differences from the isp1760, 8 bit address for
+registers and 16 bit for values, no bulk access to memory addresses,
+16 PTD's instead of 32.
+
+Following the regmap work done before add the registers, memory access
+and add the functions to support differences in setup sequences.
+
+Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
+---
+ drivers/usb/isp1760/isp1760-core.c | 118 +++++-
+ drivers/usb/isp1760/isp1760-core.h | 4 +-
+ drivers/usb/isp1760/isp1760-hcd.c | 622 ++++++++++++++++++++++-------
+ drivers/usb/isp1760/isp1760-hcd.h | 6 +-
+ drivers/usb/isp1760/isp1760-if.c | 15 +-
+ drivers/usb/isp1760/isp1760-regs.h | 240 +++++++++--
+ include/linux/usb/isp1760.h | 2 +
+ 7 files changed, 799 insertions(+), 208 deletions(-)
+
+diff --git a/drivers/usb/isp1760/isp1760-core.c b/drivers/usb/isp1760/isp1760-core.c
+index 88f233c11397..c26a586c0dca 100644
+--- a/drivers/usb/isp1760/isp1760-core.c
++++ b/drivers/usb/isp1760/isp1760-core.c
+@@ -25,7 +25,7 @@
+ #include "isp1760-regs.h"
+ #include "isp1760-udc.h"
+
+-static void isp1760_init_core(struct isp1760_device *isp)
++static int isp1760_init_core(struct isp1760_device *isp)
+ {
+ struct isp1760_hcd *hcd = &isp->hcd;
+ struct isp1760_udc *udc = &isp->udc;
+@@ -45,8 +45,25 @@ static void isp1760_init_core(struct isp1760_device *isp)
+ msleep(100);
+
+ /* Setup HW Mode Control: This assumes a level active-low interrupt */
++ if ((isp->devflags & ISP1760_FLAG_BUS_WIDTH_8) && !hcd->is_isp1763) {
++ dev_err(isp->dev, "8bit bus width not supported\n");
++ return -EINVAL;
++ }
++
++ if ((isp->devflags & ISP1760_FLAG_BUS_WIDTH_16) && hcd->is_isp1763) {
++ dev_err(isp->dev, "16bit bus width already the reset value\n");
++ return -EINVAL;
++ }
++
++ if ((isp->devflags & ISP1760_FLAG_ANALOG_OC) && hcd->is_isp1763) {
++ dev_err(isp->dev, "isp1763 analog overcurrent not available\n");
++ return -EINVAL;
++ }
++
+ if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_16)
+ isp1760_field_clear(hcd->fields, HW_DATA_BUS_WIDTH);
++ if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_8)
++ isp1760_field_set(hcd->fields, HW_DATA_BUS_WIDTH);
+ if (isp->devflags & ISP1760_FLAG_ANALOG_OC)
+ isp1760_field_set(hcd->fields, HW_ANA_DIGI_OC);
+ if (isp->devflags & ISP1760_FLAG_DACK_POL_HIGH)
+@@ -78,18 +95,24 @@ static void isp1760_init_core(struct isp1760_device *isp)
+ */
+ if ((isp->devflags & ISP1760_FLAG_ISP1761) &&
+ (isp->devflags & ISP1760_FLAG_OTG_EN)) {
+- isp1760_field_set(udc->fields, HW_DM_PULLDOWN);
+- isp1760_field_set(udc->fields, HW_DP_PULLDOWN);
+- isp1760_field_set(udc->fields, HW_OTG_DISABLE);
+- } else if (isp->devflags & ISP1760_FLAG_ISP1761) {
+- isp1760_field_set(udc->fields, HW_SW_SEL_HC_DC);
+- isp1760_field_set(udc->fields, HW_VBUS_DRV);
+- isp1760_field_set(udc->fields, HW_SEL_CP_EXT);
++ isp1760_field_set(hcd->fields, HW_DM_PULLDOWN);
++ isp1760_field_set(hcd->fields, HW_DP_PULLDOWN);
++ isp1760_field_set(hcd->fields, HW_OTG_DISABLE);
++ } else if (!hcd->is_isp1763){
++ isp1760_field_set(hcd->fields, HW_SW_SEL_HC_DC);
++ isp1760_field_set(hcd->fields, HW_VBUS_DRV);
++ isp1760_field_set(hcd->fields, HW_SEL_CP_EXT);
+ }
+
+- dev_info(isp->dev, "bus width: %u, oc: %s\n",
++ dev_info(isp->dev, "%s bus width: %u, oc: %s\n",
++ hcd->is_isp1763 ? "isp1763" : "isp1760",
++ isp->devflags & ISP1760_FLAG_BUS_WIDTH_8 ? 8 :
++ hcd->is_isp1763 ? 16 :
+ isp->devflags & ISP1760_FLAG_BUS_WIDTH_16 ? 16 : 32,
++ hcd->is_isp1763 ? "not available" :
+ isp->devflags & ISP1760_FLAG_ANALOG_OC ? "analog" : "digital");
++
++ return 0;
+ }
+
+ void isp1760_set_pullup(struct isp1760_device *isp, bool enable)
+@@ -103,6 +126,8 @@ void isp1760_set_pullup(struct isp1760_device *isp, bool enable)
+ }
+
+ /*
++ * ISP1760/61:
++ *
+ * 60kb divided in:
+ * - 32 blocks @ 256 bytes
+ * - 20 blocks @ 1024 bytes
+@@ -116,38 +141,72 @@ static const struct isp1760_memory_layout isp176x_memory_conf = {
+ .blocks[2] = 4,
+ .blocks_size[2] = 8192,
+
+- .ptd_num = 32,
++ .slot_num = 32,
+ .payload_blocks = 32 + 20 + 4,
+ .payload_area_size = 0xf000,
+ };
+
++/*
++ * ISP1763:
++ *
++ * 20kb divided in:
++ * - 8 blocks @ 256 bytes
++ * - 2 blocks @ 1024 bytes
++ * - 4 blocks @ 4096 bytes
++ */
++static const struct isp1760_memory_layout isp1763_memory_conf = {
++ .blocks[0] = 8,
++ .blocks_size[0] = 256,
++ .blocks[1] = 2,
++ .blocks_size[1] = 1024,
++ .blocks[2] = 4,
++ .blocks_size[2] = 4096,
++
++ .slot_num = 16,
++ .payload_blocks = 8 + 2 + 4,
++ .payload_area_size = 0x5000,
++};
++
+ static const struct regmap_config isp1760_hc_regmap_conf = {
+ .name = "isp1760-hc",
+ .reg_bits = 16,
++ .reg_stride = 4,
+ .val_bits = 32,
+ .fast_io = true,
+- .max_register = ISP176x_HC_MEMORY,
++ .max_register = ISP176x_HC_OTG_CTRL_CLEAR,
+ .volatile_table = &isp176x_hc_volatile_table,
+ };
+
+-static const struct regmap_config isp1760_dc_regmap_conf = {
+- .name = "isp1760-dc",
++static const struct regmap_config isp1763_hc_regmap_conf = {
++ .name = "isp1763-hc",
++ .reg_bits = 8,
++ .reg_stride = 2,
++ .val_bits = 16,
++ .fast_io = true,
++ .max_register = ISP1763_HC_OTG_CTRL_CLEAR,
++ .volatile_table = &isp1763_hc_volatile_table,
++};
++
++static const struct regmap_config isp1761_dc_regmap_conf = {
++ .name = "isp1761-dc",
+ .reg_bits = 16,
++ .reg_stride = 4,
+ .val_bits = 32,
+ .fast_io = true,
+- .max_register = ISP1761_DC_OTG_CTRL_CLEAR,
++ .max_register = ISP176x_DC_TESTMODE,
+ .volatile_table = &isp176x_dc_volatile_table,
+ };
+
+ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
+ struct device *dev, unsigned int devflags)
+ {
++ bool udc_disabled = !(devflags & ISP1760_FLAG_ISP1761);
++ const struct regmap_config *hc_regmap;
++ const struct reg_field *hc_reg_fields;
+ struct isp1760_device *isp;
+ struct isp1760_hcd *hcd;
+ struct isp1760_udc *udc;
+- bool udc_disabled = !(devflags & ISP1760_FLAG_ISP1761);
+ struct regmap_field *f;
+- void __iomem *base;
+ int ret;
+ int i;
+
+@@ -168,6 +227,16 @@ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
+ hcd = &isp->hcd;
+ udc = &isp->udc;
+
++ hcd->is_isp1763 = !!(devflags & ISP1760_FLAG_ISP1763);
++
++ if (hcd->is_isp1763) {
++ hc_regmap = &isp1763_hc_regmap_conf;
++ hc_reg_fields = &isp1763_hc_reg_fields[0];
++ } else {
++ hc_regmap = &isp1760_hc_regmap_conf;
++ hc_reg_fields = &isp1760_hc_reg_fields[0];
++ }
++
+ isp->rst_gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH);
+ if (IS_ERR(isp->rst_gpio))
+ return PTR_ERR(isp->rst_gpio);
+@@ -176,20 +245,20 @@ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
+ if (IS_ERR(hcd->base))
+ return PTR_ERR(hcd->base);
+
+- hcd->regs = devm_regmap_init_mmio(dev, base, &isp1760_hc_regmap_conf);
++ hcd->regs = devm_regmap_init_mmio(dev, hcd->base, hc_regmap);
+ if (IS_ERR(hcd->regs))
+ return PTR_ERR(hcd->regs);
+
+ for (i = 0; i < HC_FIELD_MAX; i++) {
+- f = devm_regmap_field_alloc(dev, hcd->regs,
+- isp1760_hc_reg_fields[i]);
++ f = devm_regmap_field_alloc(dev, hcd->regs, hc_reg_fields[i]);
+ if (IS_ERR(f))
+ return PTR_ERR(f);
+
+ hcd->fields[i] = f;
+ }
+
+- udc->regs = devm_regmap_init_mmio(dev, base, &isp1760_dc_regmap_conf);
++ udc->regs = devm_regmap_init_mmio(dev, hcd->base,
++ &isp1761_dc_regmap_conf);
+ if (IS_ERR(udc->regs))
+ return PTR_ERR(udc->regs);
+
+@@ -202,9 +271,14 @@ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
+ udc->fields[i] = f;
+ }
+
+- hcd->memory_layout = &isp176x_memory_conf;
++ if (hcd->is_isp1763)
++ hcd->memory_layout = &isp1763_memory_conf;
++ else
++ hcd->memory_layout = &isp176x_memory_conf;
+
+- isp1760_init_core(isp);
++ ret = isp1760_init_core(isp);
++ if (ret < 0)
++ return ret;
+
+ if (IS_ENABLED(CONFIG_USB_ISP1760_HCD) && !usb_disabled()) {
+ ret = isp1760_hcd_register(hcd, mem, irq,
+diff --git a/drivers/usb/isp1760/isp1760-core.h b/drivers/usb/isp1760/isp1760-core.h
+index 0cae69b4792c..70a1c56b2c5f 100644
+--- a/drivers/usb/isp1760/isp1760-core.h
++++ b/drivers/usb/isp1760/isp1760-core.h
+@@ -35,6 +35,8 @@ struct gpio_desc;
+ #define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */
+ #define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */
+ #define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */
++#define ISP1760_FLAG_ISP1763 0x00000200 /* Chip is ISP1763 */
++#define ISP1760_FLAG_BUS_WIDTH_8 0x00000400 /* 8-bit data bus width */
+
+ struct isp1760_device {
+ struct device *dev;
+@@ -62,7 +64,7 @@ inline static u32 isp1760_field_read(struct regmap_field **fields, u32 field)
+ }
+
+ inline static void isp1760_field_write(struct regmap_field **fields, u32 field,
+- u32 val)
++ u32 val)
+ {
+ regmap_field_write(fields[field], val);
+ }
+diff --git a/drivers/usb/isp1760/isp1760-hcd.c b/drivers/usb/isp1760/isp1760-hcd.c
+index 0f54a989dbed..c78e007578b6 100644
+--- a/drivers/usb/isp1760/isp1760-hcd.c
++++ b/drivers/usb/isp1760/isp1760-hcd.c
+@@ -92,7 +92,7 @@ struct ptd {
+ #define TO_DW2_RL(x) ((x) << 25)
+ #define FROM_DW2_RL(x) (((x) >> 25) & 0xf)
+ /* DW3 */
+-#define FROM_DW3_NRBYTESTRANSFERRED(x) ((x) & 0x7fff)
++#define FROM_DW3_NRBYTESTRANSFERRED(x) ((x) & 0x3fff)
+ #define FROM_DW3_SCS_NRBYTESTRANSFERRED(x) ((x) & 0x07ff)
+ #define TO_DW3_NAKCOUNT(x) ((x) << 19)
+ #define FROM_DW3_NAKCOUNT(x) (((x) >> 19) & 0xf)
+@@ -119,7 +119,7 @@ struct ptd {
+ /* Errata 1 */
+ #define RL_COUNTER (0)
+ #define NAK_COUNTER (0)
+-#define ERR_COUNTER (2)
++#define ERR_COUNTER (3)
+
+ struct isp1760_qtd {
+ u8 packet_type;
+@@ -171,10 +171,30 @@ static u32 isp1760_hcd_read(struct usb_hcd *hcd, u32 field)
+ return isp1760_field_read(priv->fields, field);
+ }
+
++/*
++* We need, in isp1763, to write directly the values to the portsc1
++* register so it will make the other values to trigger.
++*/
++static void isp1760_hcd_portsc1_set_clear(struct isp1760_hcd *priv, u32 field,
++ u32 val)
++{
++ u32 bit = isp1763_hc_portsc1_fields[field];
++ u32 temp = readl(priv->base + ISP1763_HC_PORTSC1);
++
++ if (val)
++ writel(temp | bit, priv->base + ISP1763_HC_PORTSC1);
++ else
++ writel(temp & ~bit, priv->base + ISP1763_HC_PORTSC1);
++}
++
+ static void isp1760_hcd_write(struct usb_hcd *hcd, u32 field, u32 val)
+ {
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
++ if (unlikely(priv->is_isp1763 &&
++ (field >= PORT_OWNER && field <= PORT_CONNECT)))
++ return isp1760_hcd_portsc1_set_clear(priv, field, val);
++
+ isp1760_field_write(priv->fields, field, val);
+ }
+
+@@ -188,28 +208,40 @@ static void isp1760_hcd_clear(struct usb_hcd *hcd, u32 field)
+ isp1760_hcd_write(hcd, field, 0);
+ }
+
+-static int isp1760_hcd_set_poll_timeout(struct usb_hcd *hcd, u32 field,
+- u32 timeout_us)
++static int isp1760_hcd_set_and_wait(struct usb_hcd *hcd, u32 field,
++ u32 timeout_us)
+ {
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+- unsigned int val;
++ u32 val;
+
+ isp1760_hcd_set(hcd, field);
+
+- return regmap_field_read_poll_timeout(priv->fields[field], val, 1, 1,
+- timeout_us);
++ return regmap_field_read_poll_timeout(priv->fields[field], val,
++ val, 10, timeout_us);
+ }
+
+-static int isp1760_hcd_clear_poll_timeout(struct usb_hcd *hcd, u32 field,
+- u32 timeout_us)
++static int isp1760_hcd_set_and_wait_swap(struct usb_hcd *hcd, u32 field,
++ u32 timeout_us)
+ {
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+- unsigned int val;
++ u32 val;
++
++ isp1760_hcd_set(hcd, field);
++
++ return regmap_field_read_poll_timeout(priv->fields[field], val,
++ !val, 10, timeout_us);
++}
++
++static int isp1760_hcd_clear_and_wait(struct usb_hcd *hcd, u32 field,
++ u32 timeout_us)
++{
++ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++ u32 val;
+
+ isp1760_hcd_clear(hcd, field);
+
+- return regmap_field_read_poll_timeout(priv->fields[field], val, 0, 1,
+- timeout_us);
++ return regmap_field_read_poll_timeout(priv->fields[field], val,
++ !val, 10, timeout_us);
+ }
+
+ static bool isp1760_hcd_is_set(struct usb_hcd *hcd, u32 field)
+@@ -217,12 +249,32 @@ static bool isp1760_hcd_is_set(struct usb_hcd *hcd, u32 field)
+ return !!isp1760_hcd_read(hcd, field);
+ }
+
++static bool isp1760_hcd_ppc_is_set(struct usb_hcd *hcd)
++{
++ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++
++ if (priv->is_isp1763)
++ return true;
++
++ return isp1760_hcd_is_set(hcd, HCS_PPC);
++}
++
++static u32 isp1760_hcd_n_ports(struct usb_hcd *hcd)
++{
++ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++
++ if (priv->is_isp1763)
++ return 1;
++
++ return isp1760_hcd_read(hcd, HCS_N_PORTS);
++}
++
+ /*
+ * Access functions for isp176x memory (offset >= 0x0400).
+ *
+ * bank_reads8() reads memory locations prefetched by an earlier write to
+ * HC_MEMORY_REG (see isp176x datasheet). Unless you want to do fancy multi-
+- * bank optimizations, you should use the more generic mem_reads8() below.
++ * bank optimizations, you should use the more generic mem_read() below.
+ *
+ * For access to ptd memory, use the specialized ptd_read() and ptd_write()
+ * below.
+@@ -277,19 +329,61 @@ static void bank_reads8(void __iomem *src_base, u32 src_offset, u32 bank_addr,
+ }
+ }
+
+-static void mem_reads8(struct usb_hcd *hcd, void __iomem *src_base,
+- u32 src_offset, void *dst, u32 bytes)
++static void isp1760_mem_read(struct usb_hcd *hcd, u32 src_offset, void *dst,
++ u32 bytes)
+ {
++ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++
+ isp1760_hcd_write(hcd, MEM_BANK_SEL, ISP_BANK_0);
+ isp1760_hcd_write(hcd, MEM_START_ADDR, src_offset);
++ ndelay(100);
+
+- ndelay(90);
++ bank_reads8(priv->base, src_offset, ISP_BANK_0, dst, bytes);
++}
++
++/*
++ * ISP1763 does not have the banks direct host controller memory access,
++ * needs to use the HC_DATA register. Add data read/write according to this,
++ * and also adjust 16bit access, here is assumed that the address was already
++ * written in the MEM_START_ADDR field.
++ */
++static void isp1763_mem_read(struct usb_hcd *hcd, u16 srcaddr,
++ u16 *dstptr, u32 bytes)
++{
++ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++
++ /* Write the starting device address to the hcd memory register */
++ //reg_write16(base, HC_MEMORY_REG, srcaddr);
++ isp1760_reg_write(priv->regs, ISP1763_HC_MEMORY, srcaddr);
++ ndelay(100); /* Delay between consecutive access */
++
++ /* As long there are at least 16-bit to read ... */
++ while (bytes >= 2) {
++ *dstptr = __raw_readw(priv->base + ISP1763_HC_DATA);
++ bytes -= 2;
++ dstptr++;
++ }
++
++ /* If there are no more bytes to read, return */
++ if (bytes <= 0)
++ return;
+
+- bank_reads8(src_base, src_offset, ISP_BANK_0, dst, bytes);
++ *((u8 *)dstptr) = (u8)(readw(priv->base + ISP1763_HC_DATA) & 0xFF);
+ }
+
+-static void mem_writes8(void __iomem *dst_base, u32 dst_offset,
+- __u32 const *src, u32 bytes)
++static void mem_read(struct usb_hcd *hcd, u32 src_offset, __u32 *dst,
++ u32 bytes)
++{
++ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++
++ if (!priv->is_isp1763)
++ return isp1760_mem_read(hcd, src_offset, (u16 *)dst, bytes);
++
++ isp1763_mem_read(hcd, (u16)src_offset, (u16 *)dst, bytes);
++}
++
++static void isp1760_mem_write(void __iomem *dst_base, u32 dst_offset,
++ __u32 const *src, u32 bytes)
+ {
+ __u32 __iomem *dst;
+
+@@ -323,33 +417,136 @@ static void mem_writes8(void __iomem *dst_base, u32 dst_offset,
+ __raw_writel(*src, dst);
+ }
+
++static void isp1763_mem_write(struct usb_hcd *hcd, u16 dstaddr, u16 *src,
++ u32 bytes)
++{
++ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++
++ /* Write the starting device address to the hcd memory register */
++ isp1760_reg_write(priv->regs, ISP1763_HC_MEMORY, dstaddr);
++ ndelay(100); /* Delay between consecutive access */
++
++ while (bytes >= 2) {
++ /* Get and write the data; then adjust the data ptr and len */
++ __raw_writew(*src, priv->base + ISP1763_HC_DATA);
++ bytes -= 2;
++ src++;
++ }
++
++ /* If there are no more bytes to process, return */
++ if (bytes <= 0)
++ return;
++
++ /*
++ * The only way to get here is if there is a single byte left,
++ * get it and write it to the data reg;
++ */
++ writew(*((u8 *)src), priv->base + ISP1763_HC_DATA);
++}
++
++static void mem_write(struct usb_hcd *hcd, u32 dst_offset, __u32 *src,
++ u32 bytes)
++{
++ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++
++ if (!priv->is_isp1763)
++ return isp1760_mem_write(priv->base, dst_offset, src, bytes);
++
++ isp1763_mem_write(hcd, dst_offset, (u16 *)src, bytes);
++}
++
++
+ /*
+ * Read and write ptds. 'ptd_offset' should be one of ISO_PTD_OFFSET,
+- * INT_PTD_OFFSET, and ATL_PTD_OFFSET. 'slot' should be less than 32.
++ * INT_PTD_OFFSET, and ATL_PTD_OFFSET. 'slot' should be less than 32/16.
+ */
+-static void ptd_read(struct usb_hcd *hcd, void __iomem *base,
+- u32 ptd_offset, u32 slot, struct ptd *ptd)
++static void isp1760_ptd_read(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
++ struct ptd *ptd)
+ {
++ u16 src_offset = ptd_offset + slot * sizeof(*ptd);
++ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++
+ isp1760_hcd_write(hcd, MEM_BANK_SEL, ISP_BANK_0);
+- isp1760_hcd_write(hcd, MEM_START_ADDR,
+- ptd_offset + slot * sizeof(*ptd));
++ isp1760_hcd_write(hcd, MEM_START_ADDR, src_offset);
+ ndelay(90);
+- bank_reads8(base, ptd_offset + slot*sizeof(*ptd), ISP_BANK_0,
+- (void *) ptd, sizeof(*ptd));
++
++ bank_reads8(priv->base, src_offset, ISP_BANK_0, (void *) ptd,
++ sizeof(*ptd));
++}
++
++static void isp1763_ptd_read(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
++ struct ptd *ptd)
++{
++ u16 src_offset = ptd_offset + slot * sizeof(*ptd);
++ struct ptd le32_ptd;
++
++ isp1763_mem_read(hcd, src_offset, (u16 *)&le32_ptd, sizeof(le32_ptd));
++ /* Normalize the data obtained */
++ ptd->dw0 = le32_to_cpu(le32_ptd.dw0);
++ ptd->dw1 = le32_to_cpu(le32_ptd.dw1);
++ ptd->dw2 = le32_to_cpu(le32_ptd.dw2);
++ ptd->dw3 = le32_to_cpu(le32_ptd.dw3);
++ ptd->dw4 = le32_to_cpu(le32_ptd.dw4);
++ ptd->dw5 = le32_to_cpu(le32_ptd.dw5);
++ ptd->dw6 = le32_to_cpu(le32_ptd.dw6);
++ ptd->dw7 = le32_to_cpu(le32_ptd.dw7);
++}
++
++static void ptd_read(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
++ struct ptd *ptd)
++{
++ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++
++ if (!priv->is_isp1763)
++ return isp1760_ptd_read(hcd, ptd_offset, slot, ptd);
++
++ isp1763_ptd_read(hcd, ptd_offset, slot, ptd);
+ }
+
+-static void ptd_write(void __iomem *base, u32 ptd_offset, u32 slot,
+- struct ptd *ptd)
++static void isp1763_ptd_write(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
++ struct ptd *cpu_ptd)
+ {
+- mem_writes8(base, ptd_offset + slot*sizeof(*ptd) + sizeof(ptd->dw0),
+- &ptd->dw1, 7*sizeof(ptd->dw1));
+- /* Make sure dw0 gets written last (after other dw's and after payload)
+- since it contains the enable bit */
++ u16 dst_offset = ptd_offset + slot * sizeof(*cpu_ptd);
++ struct ptd ptd;
++
++ ptd.dw0 = cpu_to_le32(cpu_ptd->dw0);
++ ptd.dw1 = cpu_to_le32(cpu_ptd->dw1);
++ ptd.dw2 = cpu_to_le32(cpu_ptd->dw2);
++ ptd.dw3 = cpu_to_le32(cpu_ptd->dw3);
++ ptd.dw4 = cpu_to_le32(cpu_ptd->dw4);
++ ptd.dw5 = cpu_to_le32(cpu_ptd->dw5);
++ ptd.dw6 = cpu_to_le32(cpu_ptd->dw6);
++ ptd.dw7 = cpu_to_le32(cpu_ptd->dw7);
++
++ isp1763_mem_write(hcd, dst_offset, (u16 *)&ptd.dw0,
++ 8 * sizeof(ptd.dw0));
++}
++
++static void isp1760_ptd_write(void __iomem *base, u32 ptd_offset, u32 slot,
++ struct ptd *ptd)
++{
++ u32 dst_offset = ptd_offset + slot * sizeof(*ptd);
++
++ /*
++ * Make sure dw0 gets written last (after other dw's and after payload)
++ * since it contains the enable bit
++ */
++ isp1760_mem_write(base, dst_offset + sizeof(ptd->dw0), &ptd->dw1,
++ 7 * sizeof(ptd->dw1));
+ wmb();
+- mem_writes8(base, ptd_offset + slot*sizeof(*ptd), &ptd->dw0,
+- sizeof(ptd->dw0));
++ isp1760_mem_write(base, dst_offset, &ptd->dw0, sizeof(ptd->dw0));
+ }
+
++static void ptd_write(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
++ struct ptd *ptd)
++{
++ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++
++ if (!priv->is_isp1763)
++ return isp1760_ptd_write(priv->base, ptd_offset, slot, ptd);
++
++ isp1763_ptd_write(hcd, ptd_offset, slot, ptd);
++}
+
+ /* memory management of the 60kb on the chip from 0x1000 to 0xffff */
+ static void init_memory(struct isp1760_hcd *priv)
+@@ -426,7 +623,7 @@ static int ehci_reset(struct usb_hcd *hcd)
+ hcd->state = HC_STATE_HALT;
+ priv->next_statechange = jiffies;
+
+- return isp1760_hcd_set_poll_timeout(hcd, CMD_RESET, 250 * 1000);
++ return isp1760_hcd_set_and_wait_swap(hcd, CMD_RESET, 250 * 1000);
+ }
+
+ static struct isp1760_qh *qh_alloc(gfp_t flags)
+@@ -457,7 +654,6 @@ static int priv_init(struct usb_hcd *hcd)
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 isoc_cache;
+ u32 isoc_thres;
+-
+ int i;
+
+ spin_lock_init(&priv->lock);
+@@ -471,9 +667,14 @@ static int priv_init(struct usb_hcd *hcd)
+ */
+ priv->periodic_size = DEFAULT_I_TDPS;
+
++ if (priv->is_isp1763) {
++ priv->i_thresh = 2;
++ return 0;
++ }
++
+ /* controllers may cache some of the periodic schedule ... */
+- isoc_cache = isp1760_hcd_read(hcd->regs, HCC_ISOC_CACHE);
+- isoc_thres = isp1760_hcd_read(hcd->regs, HCC_ISOC_THRES);
++ isoc_cache = isp1760_hcd_read(hcd, HCC_ISOC_CACHE);
++ isoc_thres = isp1760_hcd_read(hcd, HCC_ISOC_THRES);
+
+ /* full frame cache */
+ if (isoc_cache)
+@@ -487,15 +688,22 @@ static int priv_init(struct usb_hcd *hcd)
+ static int isp1760_hc_setup(struct usb_hcd *hcd)
+ {
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++ u32 atx_reset;
+ int result;
+ u32 scratch;
++ u32 pattern;
+
+- isp1760_reg_write(priv->regs, ISP176x_HC_SCRATCH, 0xdeadbabe);
++ if (priv->is_isp1763)
++ pattern = 0xdead;
++ else
++ pattern = 0xdeadbeef;
++
++ isp1760_hcd_write(hcd, HC_SCRATCH, pattern);
+
+ /* Change bus pattern */
+- scratch = isp1760_reg_read(priv->regs, ISP176x_HC_CHIP_ID);
+- scratch = isp1760_reg_read(priv->regs, ISP176x_HC_SCRATCH);
+- if (scratch != 0xdeadbabe) {
++ scratch = isp1760_hcd_read(hcd, HC_CHIP_ID_HIGH);
++ scratch = isp1760_hcd_read(hcd, HC_SCRATCH);
++ if (scratch != pattern) {
+ dev_err(hcd->self.controller, "Scratch test failed.\n");
+ return -ENODEV;
+ }
+@@ -508,13 +716,13 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
+ * the host controller through the EHCI USB Command register. The device
+ * has been reset in core code anyway, so this shouldn't matter.
+ */
+- isp1760_reg_write(priv->regs, ISP176x_HC_BUFFER_STATUS, 0);
+- isp1760_reg_write(priv->regs, ISP176x_HC_ATL_PTD_SKIPMAP,
+- NO_TRANSFER_ACTIVE);
+- isp1760_reg_write(priv->regs, ISP176x_HC_INT_PTD_SKIPMAP,
+- NO_TRANSFER_ACTIVE);
+- isp1760_reg_write(priv->regs, ISP176x_HC_ISO_PTD_SKIPMAP,
+- NO_TRANSFER_ACTIVE);
++ isp1760_hcd_clear(hcd, ISO_BUF_FILL);
++ isp1760_hcd_clear(hcd, INT_BUF_FILL);
++ isp1760_hcd_clear(hcd, ATL_BUF_FILL);
++
++ isp1760_hcd_set(hcd, HC_ATL_PTD_SKIPMAP);
++ isp1760_hcd_set(hcd, HC_INT_PTD_SKIPMAP);
++ isp1760_hcd_set(hcd, HC_ISO_PTD_SKIPMAP);
+
+ result = ehci_reset(hcd);
+ if (result)
+@@ -523,11 +731,27 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
+ /* Step 11 passed */
+
+ /* ATL reset */
+- isp1760_hcd_set(hcd, ALL_ATX_RESET);
++ if (priv->is_isp1763)
++ atx_reset = SW_RESET_RESET_ATX;
++ else
++ atx_reset = ALL_ATX_RESET;
++
++ isp1760_hcd_set(hcd, atx_reset);
+ mdelay(10);
+- isp1760_hcd_clear(hcd, ALL_ATX_RESET);
++ isp1760_hcd_clear(hcd, atx_reset);
+
+- isp1760_hcd_set(hcd, HC_INT_ENABLE);
++ if (priv->is_isp1763) {
++ isp1760_hcd_set(hcd, HW_OTG_DISABLE);
++ isp1760_hcd_set(hcd, HW_SW_SEL_HC_DC_CLEAR);
++ isp1760_hcd_set(hcd, HW_HC_2_DIS_CLEAR);
++ mdelay(10);
++
++ isp1760_hcd_set(hcd, HW_INTF_LOCK);
++ }
++
++
++ isp1760_hcd_set(hcd, HC_INT_IRQ_ENABLE);
++ isp1760_hcd_set(hcd, HC_ATL_IRQ_ENABLE);
+
+ return priv_init(hcd);
+ }
+@@ -747,45 +971,45 @@ static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot,
+ struct ptd *ptd)
+ {
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++ const struct isp1760_memory_layout *mem = priv->memory_layout;
+ int skip_map;
+
+- WARN_ON((slot < 0) || (slot > 31));
++ WARN_ON((slot < 0) || (slot > mem->slot_num - 1));
+ WARN_ON(qtd->length && !qtd->payload_addr);
+ WARN_ON(slots[slot].qtd);
+ WARN_ON(slots[slot].qh);
+ WARN_ON(qtd->status != QTD_PAYLOAD_ALLOC);
+
++ if (priv->is_isp1763)
++ ndelay(100);
++
+ /* Make sure done map has not triggered from some unlinked transfer */
+ if (ptd_offset == ATL_PTD_OFFSET) {
+- priv->atl_done_map |= isp1760_reg_read(priv->regs,
+- ISP176x_HC_ATL_PTD_DONEMAP);
++ skip_map = isp1760_hcd_read(hcd, HC_ATL_PTD_SKIPMAP);
++ isp1760_hcd_write(hcd, HC_ATL_PTD_SKIPMAP,
++ skip_map | (1 << slot));
++ priv->atl_done_map |= isp1760_hcd_read(hcd, HC_ATL_PTD_DONEMAP);
+ priv->atl_done_map &= ~(1 << slot);
+ } else {
+- priv->int_done_map |= isp1760_reg_read(priv->regs,
+- ISP176x_HC_INT_PTD_DONEMAP);
++ skip_map = isp1760_hcd_read(hcd, HC_INT_PTD_SKIPMAP);
++ isp1760_hcd_write(hcd, HC_INT_PTD_SKIPMAP,
++ skip_map | (1 << slot));
++ priv->int_done_map |= isp1760_hcd_read(hcd, HC_INT_PTD_DONEMAP);
+ priv->int_done_map &= ~(1 << slot);
+ }
+
++ skip_map &= ~(1 << slot);
+ qh->slot = slot;
+ qtd->status = QTD_XFER_STARTED;
+ slots[slot].timestamp = jiffies;
+ slots[slot].qtd = qtd;
+ slots[slot].qh = qh;
+- ptd_write(priv->base, ptd_offset, slot, ptd);
++ ptd_write(hcd, ptd_offset, slot, ptd);
+
+- if (ptd_offset == ATL_PTD_OFFSET) {
+- skip_map = isp1760_reg_read(priv->regs,
+- ISP176x_HC_ATL_PTD_SKIPMAP);
+- skip_map &= ~(1 << qh->slot);
+- isp1760_reg_write(priv->regs, ISP176x_HC_ATL_PTD_SKIPMAP,
+- skip_map);
+- } else {
+- skip_map = isp1760_reg_read(priv->regs,
+- ISP176x_HC_INT_PTD_SKIPMAP);
+- skip_map &= ~(1 << qh->slot);
+- isp1760_reg_write(priv->regs, ISP176x_HC_INT_PTD_SKIPMAP,
+- skip_map);
+- }
++ if (ptd_offset == ATL_PTD_OFFSET)
++ isp1760_hcd_write(hcd, HC_ATL_PTD_SKIPMAP, skip_map);
++ else
++ isp1760_hcd_write(hcd, HC_INT_PTD_SKIPMAP, skip_map);
+ }
+
+ static int is_short_bulk(struct isp1760_qtd *qtd)
+@@ -797,7 +1021,6 @@ static int is_short_bulk(struct isp1760_qtd *qtd)
+ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
+ struct list_head *urb_list)
+ {
+- struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ struct isp1760_qtd *qtd, *qtd_next;
+ struct urb_listitem *urb_listitem;
+ int last_qtd;
+@@ -815,10 +1038,9 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
+ if (qtd->actual_length) {
+ switch (qtd->packet_type) {
+ case IN_PID:
+- mem_reads8(hcd, priv->base,
+- qtd->payload_addr,
+- qtd->data_buffer,
+- qtd->actual_length);
++ mem_read(hcd, qtd->payload_addr,
++ qtd->data_buffer,
++ qtd->actual_length);
+ /* Fall through */
+ case OUT_PID:
+ qtd->urb->actual_length +=
+@@ -862,6 +1084,8 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
+ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
+ {
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++ const struct isp1760_memory_layout *mem = priv->memory_layout;
++ int slot_num = mem->slot_num;
+ int ptd_offset;
+ struct isp1760_slotinfo *slots;
+ int curr_slot, free_slot;
+@@ -888,7 +1112,7 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
+ }
+
+ free_slot = -1;
+- for (curr_slot = 0; curr_slot < 32; curr_slot++) {
++ for (curr_slot = 0; curr_slot < slot_num; curr_slot++) {
+ if ((free_slot == -1) && (slots[curr_slot].qtd == NULL))
+ free_slot = curr_slot;
+ if (slots[curr_slot].qh == qh)
+@@ -906,8 +1130,8 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
+ if ((qtd->length) &&
+ ((qtd->packet_type == SETUP_PID) ||
+ (qtd->packet_type == OUT_PID))) {
+- mem_writes8(priv->base, qtd->payload_addr,
+- qtd->data_buffer, qtd->length);
++ mem_write(hcd, qtd->payload_addr,
++ qtd->data_buffer, qtd->length);
+ }
+
+ qtd->status = QTD_PAYLOAD_ALLOC;
+@@ -920,7 +1144,7 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
+ "available for transfer\n", __func__);
+ */
+ /* Start xfer for this endpoint if not already done */
+- if ((curr_slot > 31) && (free_slot > -1)) {
++ if ((curr_slot > slot_num - 1) && (free_slot > -1)) {
+ if (usb_pipeint(qtd->urb->pipe))
+ create_ptd_int(qh, qtd, &ptd);
+ else
+@@ -1107,9 +1331,9 @@ static void handle_done_ptds(struct usb_hcd *hcd)
+ int modified;
+ int skip_map;
+
+- skip_map = isp1760_reg_read(priv->regs, ISP176x_HC_INT_PTD_SKIPMAP);
++ skip_map = isp1760_hcd_read(hcd, HC_INT_PTD_SKIPMAP);
+ priv->int_done_map &= ~skip_map;
+- skip_map = isp1760_reg_read(priv->regs, ISP176x_HC_ATL_PTD_SKIPMAP);
++ skip_map = isp1760_hcd_read(hcd, HC_ATL_PTD_SKIPMAP);
+ priv->atl_done_map &= ~skip_map;
+
+ modified = priv->int_done_map || priv->atl_done_map;
+@@ -1127,7 +1351,7 @@ static void handle_done_ptds(struct usb_hcd *hcd)
+ continue;
+ }
+ ptd_offset = INT_PTD_OFFSET;
+- ptd_read(hcd, priv->base, INT_PTD_OFFSET, slot, &ptd);
++ ptd_read(hcd, INT_PTD_OFFSET, slot, &ptd);
+ state = check_int_transfer(hcd, &ptd,
+ slots[slot].qtd->urb);
+ } else {
+@@ -1142,7 +1366,7 @@ static void handle_done_ptds(struct usb_hcd *hcd)
+ continue;
+ }
+ ptd_offset = ATL_PTD_OFFSET;
+- ptd_read(hcd, priv->base, ATL_PTD_OFFSET, slot, &ptd);
++ ptd_read(hcd, ATL_PTD_OFFSET, slot, &ptd);
+ state = check_atl_transfer(hcd, &ptd,
+ slots[slot].qtd->urb);
+ }
+@@ -1243,19 +1467,18 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
+ if (!(hcd->state & HC_STATE_RUNNING))
+ goto leave;
+
+- imask = isp1760_reg_read(priv->regs, ISP176x_HC_INTERRUPT);
++ imask = isp1760_hcd_read(hcd, HC_INTERRUPT);
+ if (unlikely(!imask))
+ goto leave;
+- isp1760_reg_write(priv->regs, ISP176x_HC_INTERRUPT, imask); /* Clear */
++ isp1760_reg_write(priv->regs, ISP1763_HC_INTERRUPT, imask);
+
+- priv->int_done_map |= isp1760_reg_read(priv->regs,
+- ISP176x_HC_INT_PTD_DONEMAP);
+- priv->atl_done_map |= isp1760_reg_read(priv->regs,
+- ISP176x_HC_ATL_PTD_DONEMAP);
++ priv->int_done_map |= isp1760_hcd_read(hcd, HC_INT_PTD_DONEMAP);
++ priv->atl_done_map |= isp1760_hcd_read(hcd, HC_ATL_PTD_DONEMAP);
+
+ handle_done_ptds(hcd);
+
+ irqret = IRQ_HANDLED;
++
+ leave:
+ spin_unlock(&priv->lock);
+
+@@ -1296,17 +1519,18 @@ static void errata2_function(struct timer_list *unused)
+ {
+ struct usb_hcd *hcd = errata2_timer_hcd;
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++ const struct isp1760_memory_layout *mem = priv->memory_layout;
+ int slot;
+ struct ptd ptd;
+ unsigned long spinflags;
+
+ spin_lock_irqsave(&priv->lock, spinflags);
+
+- for (slot = 0; slot < 32; slot++)
++ for (slot = 0; slot < mem->slot_num; slot++)
+ if (priv->atl_slots[slot].qh && time_after(jiffies,
+ priv->atl_slots[slot].timestamp +
+ msecs_to_jiffies(SLOT_TIMEOUT))) {
+- ptd_read(hcd, priv->base, ATL_PTD_OFFSET, slot, &ptd);
++ ptd_read(hcd, ATL_PTD_OFFSET, slot, &ptd);
+ if (!FROM_DW0_VALID(ptd.dw0) &&
+ !FROM_DW3_ACTIVE(ptd.dw3))
+ priv->atl_done_map |= 1 << slot;
+@@ -1321,23 +1545,114 @@ static void errata2_function(struct timer_list *unused)
+ add_timer(&errata2_timer);
+ }
+
++static int isp1763_run(struct usb_hcd *hcd)
++{
++ struct isp1760_hcd *priv = hcd_to_priv(hcd);
++ int retval;
++ u32 chipid_h;
++ u32 chipid_l;
++ u32 chip_rev;
++ u32 ptd_atl_int;
++ u32 ptd_iso;
++
++ hcd->uses_new_polling = 1;
++ hcd->state = HC_STATE_RUNNING;
++
++ chipid_h = isp1760_hcd_read(hcd, HC_CHIP_ID_HIGH);
++ chipid_l = isp1760_hcd_read(hcd, HC_CHIP_ID_LOW);
++ chip_rev = isp1760_hcd_read(hcd, HC_CHIP_REV);
++ dev_info(hcd->self.controller, "USB ISP %02x%02x HW rev. %d started\n",
++ chipid_h, chipid_l, chip_rev);
++
++ isp1760_hcd_clear(hcd, ISO_BUF_FILL);
++ isp1760_hcd_clear(hcd, INT_BUF_FILL);
++ isp1760_hcd_clear(hcd, ATL_BUF_FILL);
++
++ isp1760_hcd_set(hcd, HC_ATL_PTD_SKIPMAP);
++ isp1760_hcd_set(hcd, HC_INT_PTD_SKIPMAP);
++ isp1760_hcd_set(hcd, HC_ISO_PTD_SKIPMAP);
++ ndelay(100);
++ isp1760_hcd_clear(hcd, HC_ATL_PTD_DONEMAP);
++ isp1760_hcd_clear(hcd, HC_INT_PTD_DONEMAP);
++ isp1760_hcd_clear(hcd, HC_ISO_PTD_DONEMAP);
++
++
++ isp1760_hcd_set(hcd, HW_OTG_DISABLE);
++ isp1760_reg_write(priv->regs, ISP1763_HC_OTG_CTRL_CLEAR, (1 << 7));
++ isp1760_reg_write(priv->regs, ISP1763_HC_OTG_CTRL_CLEAR, (1 << 15));
++ mdelay(10);
++
++ isp1760_hcd_set(hcd, HC_INT_IRQ_ENABLE);
++ isp1760_hcd_set(hcd, HC_ATL_IRQ_ENABLE);
++
++ isp1760_hcd_set(hcd, HW_GLOBAL_INTR_EN);
++
++ isp1760_hcd_clear(hcd, HC_ATL_IRQ_MASK_AND);
++ isp1760_hcd_clear(hcd, HC_INT_IRQ_MASK_AND);
++ isp1760_hcd_clear(hcd, HC_ISO_IRQ_MASK_AND);
++
++ isp1760_hcd_set(hcd, HC_ATL_IRQ_MASK_OR);
++ isp1760_hcd_set(hcd, HC_INT_IRQ_MASK_OR);
++ isp1760_hcd_set(hcd, HC_ISO_IRQ_MASK_OR);
++
++ ptd_atl_int = 0x8000;
++ ptd_iso = 0x0001;
++
++ isp1760_hcd_write(hcd, HC_ATL_PTD_LASTPTD, ptd_atl_int);
++ isp1760_hcd_write(hcd, HC_INT_PTD_LASTPTD, ptd_atl_int);
++ isp1760_hcd_write(hcd, HC_ISO_PTD_LASTPTD, ptd_iso);
++
++ isp1760_hcd_set(hcd, ATL_BUF_FILL);
++ isp1760_hcd_set(hcd, INT_BUF_FILL);
++
++ isp1760_hcd_clear(hcd, CMD_LRESET);
++ isp1760_hcd_clear(hcd, CMD_RESET);
++
++ retval = isp1760_hcd_set_and_wait(hcd, CMD_RUN, 250 * 1000);
++ if (retval)
++ return retval;
++
++ down_write(&ehci_cf_port_reset_rwsem);
++ retval = isp1760_hcd_set_and_wait(hcd, FLAG_CF, 250 * 1000);
++ up_write(&ehci_cf_port_reset_rwsem);
++ retval = 0;
++ if (retval)
++ return retval;
++
++ return 0;
++}
++
+ static int isp1760_run(struct usb_hcd *hcd)
+ {
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int retval;
+- u32 chipid;
++ u32 chipid_h;
++ u32 chipid_l;
++ u32 chip_rev;
++ u32 ptd_atl_int;
++ u32 ptd_iso;
++
++ /*
++ * ISP1763 have some differences in the setup and order to enable
++ * the ports, disable otg, setup buffers, and ATL, INT, ISO status.
++ * So, just handle it a separate sequence.
++ */
++ if (priv->is_isp1763)
++ return isp1763_run(hcd);
+
+ hcd->uses_new_polling = 1;
+
+ hcd->state = HC_STATE_RUNNING;
+
+ /* Set PTD interrupt AND & OR maps */
+- isp1760_reg_write(priv->regs, ISP176x_HC_ATL_IRQ_MASK_AND, 0);
+- isp1760_reg_write(priv->regs, ISP176x_HC_ATL_IRQ_MASK_OR, 0xffffffff);
+- isp1760_reg_write(priv->regs, ISP176x_HC_INT_IRQ_MASK_AND, 0);
+- isp1760_reg_write(priv->regs, ISP176x_HC_INT_IRQ_MASK_OR, 0xffffffff);
+- isp1760_reg_write(priv->regs, ISP176x_HC_ISO_IRQ_MASK_AND, 0);
+- isp1760_reg_write(priv->regs, ISP176x_HC_ISO_IRQ_MASK_OR, 0xffffffff);
++ isp1760_hcd_clear(hcd, HC_ATL_IRQ_MASK_AND);
++ isp1760_hcd_clear(hcd, HC_INT_IRQ_MASK_AND);
++ isp1760_hcd_clear(hcd, HC_ISO_IRQ_MASK_AND);
++
++ isp1760_hcd_set(hcd, HC_ATL_IRQ_MASK_OR);
++ isp1760_hcd_set(hcd, HC_INT_IRQ_MASK_OR);
++ isp1760_hcd_set(hcd, HC_ISO_IRQ_MASK_OR);
++
+ /* step 23 passed */
+
+ isp1760_hcd_set(hcd, HW_GLOBAL_INTR_EN);
+@@ -1345,7 +1660,7 @@ static int isp1760_run(struct usb_hcd *hcd)
+ isp1760_hcd_clear(hcd, CMD_LRESET);
+ isp1760_hcd_clear(hcd, CMD_RESET);
+
+- retval = isp1760_hcd_set_poll_timeout(hcd, CMD_RUN, 250 * 1000);
++ retval = isp1760_hcd_set_and_wait(hcd, CMD_RUN, 250 * 1000);
+ if (retval)
+ return retval;
+
+@@ -1356,7 +1671,7 @@ static int isp1760_run(struct usb_hcd *hcd)
+ */
+ down_write(&ehci_cf_port_reset_rwsem);
+
+- retval = isp1760_hcd_set_poll_timeout(hcd, FLAG_CF, 250 * 1000);
++ retval = isp1760_hcd_set_and_wait(hcd, FLAG_CF, 250 * 1000);
+ up_write(&ehci_cf_port_reset_rwsem);
+ if (retval)
+ return retval;
+@@ -1366,19 +1681,25 @@ static int isp1760_run(struct usb_hcd *hcd)
+ errata2_timer.expires = jiffies + msecs_to_jiffies(SLOT_CHECK_PERIOD);
+ add_timer(&errata2_timer);
+
+- chipid = isp1760_reg_read(priv->regs, ISP176x_HC_CHIP_ID);
+- dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n",
+- chipid & 0xffff, chipid >> 16);
++ chipid_h = isp1760_hcd_read(hcd, HC_CHIP_ID_HIGH);
++ chipid_l = isp1760_hcd_read(hcd, HC_CHIP_ID_LOW);
++ chip_rev = isp1760_hcd_read(hcd, HC_CHIP_REV);
++ dev_info(hcd->self.controller, "USB ISP %02x%02x HW rev. %d started\n",
++ chipid_h, chipid_l, chip_rev);
+
+ /* PTD Register Init Part 2, Step 28 */
+
+ /* Setup registers controlling PTD checking */
+- isp1760_reg_write(priv->regs, ISP176x_HC_ATL_PTD_LASTPTD, 0x80000000);
+- isp1760_reg_write(priv->regs, ISP176x_HC_INT_PTD_LASTPTD, 0x80000000);
+- isp1760_reg_write(priv->regs, ISP176x_HC_ISO_PTD_LASTPTD, 0x00000001);
+- isp1760_reg_write(priv->regs, ISP176x_HC_ATL_PTD_SKIPMAP, 0xffffffff);
+- isp1760_reg_write(priv->regs, ISP176x_HC_INT_PTD_SKIPMAP, 0xffffffff);
+- isp1760_reg_write(priv->regs, ISP176x_HC_ISO_PTD_SKIPMAP, 0xffffffff);
++ ptd_atl_int = 0x80000000;
++ ptd_iso = 0x00000001;
++
++ isp1760_hcd_write(hcd, HC_ATL_PTD_LASTPTD, ptd_atl_int);
++ isp1760_hcd_write(hcd, HC_INT_PTD_LASTPTD, ptd_atl_int);
++ isp1760_hcd_write(hcd, HC_ISO_PTD_LASTPTD, ptd_iso);
++
++ isp1760_hcd_set(hcd, HC_ATL_PTD_SKIPMAP);
++ isp1760_hcd_set(hcd, HC_INT_PTD_SKIPMAP);
++ isp1760_hcd_set(hcd, HC_ISO_PTD_SKIPMAP);
+
+ isp1760_hcd_set(hcd, ATL_BUF_FILL);
+ isp1760_hcd_set(hcd, INT_BUF_FILL);
+@@ -1619,19 +1940,16 @@ static void kill_transfer(struct usb_hcd *hcd, struct urb *urb,
+ /* We need to forcefully reclaim the slot since some transfers never
+ return, e.g. interrupt transfers and NAKed bulk transfers. */
+ if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) {
+- skip_map = isp1760_reg_read(priv->regs,
+- ISP176x_HC_ATL_PTD_SKIPMAP);
++ skip_map = isp1760_hcd_read(hcd, HC_ATL_PTD_SKIPMAP);
+ skip_map |= (1 << qh->slot);
+- isp1760_reg_write(priv->regs, ISP176x_HC_ATL_PTD_SKIPMAP,
+- skip_map);
++ isp1760_hcd_write(hcd, HC_ATL_PTD_SKIPMAP, skip_map);
++ ndelay(100);
+ priv->atl_slots[qh->slot].qh = NULL;
+ priv->atl_slots[qh->slot].qtd = NULL;
+ } else {
+- skip_map = isp1760_reg_read(priv->regs,
+- ISP176x_HC_INT_PTD_SKIPMAP);
++ skip_map = isp1760_hcd_read(hcd, HC_INT_PTD_SKIPMAP);
+ skip_map |= (1 << qh->slot);
+- isp1760_reg_write(priv->regs, ISP176x_HC_INT_PTD_SKIPMAP,
+- skip_map);
++ isp1760_hcd_write(hcd, HC_INT_PTD_SKIPMAP, skip_map);
+ priv->int_slots[qh->slot].qh = NULL;
+ priv->int_slots[qh->slot].qtd = NULL;
+ }
+@@ -1787,7 +2105,7 @@ static void isp1760_hub_descriptor(struct isp1760_hcd *priv,
+ int ports;
+ u16 temp;
+
+- ports = isp1760_hcd_read(priv->hcd, HCS_N_PORTS);
++ ports = isp1760_hcd_n_ports(priv->hcd);
+
+ desc->bDescriptorType = USB_DT_HUB;
+ /* priv 1.0, 2.3.9 says 20ms max */
+@@ -1804,7 +2122,7 @@ static void isp1760_hub_descriptor(struct isp1760_hcd *priv,
+
+ /* per-port overcurrent reporting */
+ temp = HUB_CHAR_INDV_PORT_OCPM;
+- if (isp1760_hcd_is_set(priv->hcd, HCS_PPC))
++ if (isp1760_hcd_ppc_is_set(priv->hcd))
+ /* per-port power control */
+ temp |= HUB_CHAR_INDV_PORT_LPSM;
+ else
+@@ -1841,11 +2159,12 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ {
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 status;
++ u32 temp;
+ unsigned long flags;
+ int retval = 0;
+ int ports;
+
+- ports = isp1760_hcd_read(hcd, HCS_N_PORTS);
++ ports = isp1760_hcd_n_ports(hcd);
+
+ /*
+ * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
+@@ -1904,7 +2223,7 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ /* we auto-clear this feature */
+ break;
+ case USB_PORT_FEAT_POWER:
+- if (isp1760_hcd_is_set(hcd, HCS_PPC))
++ if (isp1760_hcd_ppc_is_set(hcd))
+ isp1760_hcd_clear(hcd, PORT_POWER);
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
+@@ -1919,7 +2238,7 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ default:
+ goto error;
+ }
+- isp1760_reg_read(priv->regs, ISP176x_HC_USBCMD);
++ isp1760_hcd_read(hcd, CMD_RUN);
+ break;
+ case GetHubDescriptor:
+ isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *)
+@@ -1939,7 +2258,6 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ if (isp1760_hcd_is_set(hcd, PORT_CSC))
+ status |= USB_PORT_STAT_C_CONNECTION << 16;
+
+-
+ /* whoever resumes must GetPortStatus to complete it!! */
+ if (isp1760_hcd_is_set(hcd, PORT_RESUME)) {
+ dev_err(hcd->self.controller, "Port resume should be skipped.\n");
+@@ -1962,7 +2280,7 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ /* stop resume signaling */
+ isp1760_hcd_clear(hcd, PORT_CSC);
+
+- retval = isp1760_hcd_clear_poll_timeout(hcd,
++ retval = isp1760_hcd_clear_and_wait(hcd,
+ PORT_RESUME, 2000);
+ if (retval != 0) {
+ dev_err(hcd->self.controller,
+@@ -1983,9 +2301,8 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ /* REVISIT: some hardware needs 550+ usec to clear
+ * this bit; seems too long to spin routinely...
+ */
+- retval = isp1760_hcd_clear_poll_timeout(hcd,
+- PORT_RESET,
+- 750);
++ retval = isp1760_hcd_clear_and_wait(hcd, PORT_RESET,
++ 750);
+ if (retval != 0) {
+ dev_err(hcd->self.controller, "port %d reset error %d\n",
+ wIndex + 1, retval);
+@@ -2036,6 +2353,7 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
++
+ if (isp1760_hcd_is_set(hcd, PORT_OWNER))
+ break;
+
+@@ -2052,7 +2370,7 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ isp1760_hcd_set(hcd, PORT_SUSPEND);
+ break;
+ case USB_PORT_FEAT_POWER:
+- if (isp1760_hcd_is_set(hcd, HCS_PPC))
++ if (isp1760_hcd_ppc_is_set(hcd))
+ isp1760_hcd_set(hcd, PORT_POWER);
+ break;
+ case USB_PORT_FEAT_RESET:
+@@ -2067,21 +2385,44 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ (isp1760_hcd_read(hcd, PORT_LSTATUS) == 1)) {
+ isp1760_hcd_set(hcd, PORT_OWNER);
+ } else {
+- isp1760_hcd_set(hcd, PORT_RESET);
+- isp1760_hcd_clear(hcd, PORT_PE);
++ temp = isp1760_reg_read(priv->regs, ISP1763_HC_PORTSC1);
++ //isp1760_hcd_set(hcd, PORT_RESET);
++ //isp1760_hcd_clear(hcd, PORT_PE);
++ temp |= (1 << 8);
++ temp &= ~(1 << 2);
+
++ writel(temp, priv->base + ISP1763_HC_PORTSC1);
+ /*
+ * caller must wait, then call GetPortStatus
+ * usb 2.0 spec says 50 ms resets on root
+ */
+ priv->reset_done = jiffies +
+ msecs_to_jiffies(50);
++
++ mdelay(50);
++
++ temp &= ~(1 << 8);
++ writel(temp, priv->base + ISP1763_HC_PORTSC1);
++
++ while (readl(priv->base + ISP1763_HC_PORTSC1) & (1 << 8))
++ continue;
++
++ temp |= (1 << 2);
++ writel(temp, priv->base + ISP1763_HC_PORTSC1);
++ /*retval = isp1760_hcd_clear_and_wait(hcd,
++ PORT_RESET,
++ 90000);
++ if (retval)
++ goto error;
++
++ isp1760_hcd_set(hcd, PORT_PE);
++ */
+ }
+ break;
+ default:
+ goto error;
+ }
+- isp1760_reg_read(priv->regs, ISP176x_HC_USBCMD);
++ isp1760_reg_read(priv->regs, ISP1763_HC_USBCMD);
+ break;
+
+ default:
+@@ -2216,22 +2557,14 @@ int isp1760_hcd_register(struct isp1760_hcd *priv, struct resource *mem,
+
+ priv->hcd = hcd;
+
+- priv->memory_pool = kcalloc(mem_layout->payload_blocks,
+- sizeof(struct isp1760_memory_chunk),
+- GFP_KERNEL);
+- if (!priv->memory_pool) {
+- ret = -ENOMEM;
+- goto put_hcd;
+- }
+-
+- priv->atl_slots = kcalloc(mem_layout->ptd_num,
++ priv->atl_slots = kcalloc(mem_layout->slot_num,
+ sizeof(struct isp1760_slotinfo), GFP_KERNEL);
+ if (!priv->atl_slots) {
+ ret = -ENOMEM;
+- goto free_mem_pool;
++ goto put_hcd;
+ }
+
+- priv->int_slots = kcalloc(mem_layout->ptd_num,
++ priv->int_slots = kcalloc(mem_layout->slot_num,
+ sizeof(struct isp1760_slotinfo), GFP_KERNEL);
+ if (!priv->int_slots) {
+ ret = -ENOMEM;
+@@ -2259,8 +2592,6 @@ int isp1760_hcd_register(struct isp1760_hcd *priv, struct resource *mem,
+ kfree(priv->int_slots);
+ free_atl_slots:
+ kfree(priv->atl_slots);
+-free_mem_pool:
+- kfree(priv->memory_pool);
+ put_hcd:
+ usb_put_hcd(hcd);
+ return ret;
+@@ -2275,5 +2606,4 @@ void isp1760_hcd_unregister(struct isp1760_hcd *priv)
+ usb_put_hcd(priv->hcd);
+ kfree(priv->atl_slots);
+ kfree(priv->int_slots);
+- kfree(priv->memory_pool);
+ }
+diff --git a/drivers/usb/isp1760/isp1760-hcd.h b/drivers/usb/isp1760/isp1760-hcd.h
+index e5e784b9046b..e20a46ae9dbe 100644
+--- a/drivers/usb/isp1760/isp1760-hcd.h
++++ b/drivers/usb/isp1760/isp1760-hcd.h
+@@ -19,13 +19,14 @@ struct isp1760_slotinfo {
+ };
+
+ /* chip memory management */
++#define ISP176x_BLOCK_MAX 32 + 20 + 4
+ #define ISP176x_BLOCK_NUM 3
+
+ struct isp1760_memory_layout {
+ unsigned int blocks[ISP176x_BLOCK_NUM];
+ unsigned int blocks_size[ISP176x_BLOCK_NUM];
+
+- unsigned int ptd_num;
++ unsigned int slot_num;
+ unsigned int payload_blocks;
+ unsigned int payload_area_size;
+ };
+@@ -52,6 +53,7 @@ struct isp1760_hcd {
+ struct regmap *regs;
+ struct regmap_field *fields[HC_FIELD_MAX];
+
++ bool is_isp1763;
+ const struct isp1760_memory_layout *memory_layout;
+
+ spinlock_t lock;
+@@ -59,7 +61,7 @@ struct isp1760_hcd {
+ int atl_done_map;
+ struct isp1760_slotinfo *int_slots;
+ int int_done_map;
+- struct isp1760_memory_chunk *memory_pool;
++ struct isp1760_memory_chunk memory_pool[ISP176x_BLOCK_MAX];
+ struct list_head qh_list[QH_END];
+
+ /* periodic schedule support */
+diff --git a/drivers/usb/isp1760/isp1760-if.c b/drivers/usb/isp1760/isp1760-if.c
+index abfba9f5ec23..306a047d5227 100644
+--- a/drivers/usb/isp1760/isp1760-if.c
++++ b/drivers/usb/isp1760/isp1760-if.c
+@@ -209,10 +209,15 @@ static int isp1760_plat_probe(struct platform_device *pdev)
+ if (of_device_is_compatible(dp, "nxp,usb-isp1761"))
+ devflags |= ISP1760_FLAG_ISP1761;
+
++ if (of_device_is_compatible(dp, "nxp,usb-isp1763"))
++ devflags |= ISP1760_FLAG_ISP1763;
++
+ /* Some systems wire up only 16 of the 32 data lines */
+ of_property_read_u32(dp, "bus-width", &bus_width);
+- if (bus_width == 16)
++ if (bus_width == 16 && !(devflags & ISP1760_FLAG_ISP1763))
+ devflags |= ISP1760_FLAG_BUS_WIDTH_16;
++ else if (bus_width == 8)
++ devflags |= ISP1760_FLAG_BUS_WIDTH_8;
+
+ if (of_property_read_bool(dp, "port1-otg"))
+ devflags |= ISP1760_FLAG_OTG_EN;
+@@ -231,8 +236,13 @@ static int isp1760_plat_probe(struct platform_device *pdev)
+
+ if (pdata->is_isp1761)
+ devflags |= ISP1760_FLAG_ISP1761;
+- if (pdata->bus_width_16)
++ else if (pdata->is_isp1763)
++ devflags |= ISP1760_FLAG_ISP1763;
++
++ if (pdata->bus_width_16 && !pdata->is_isp1763)
+ devflags |= ISP1760_FLAG_BUS_WIDTH_16;
++ else if (pdata->bus_width_8)
++ devflags |= ISP1760_FLAG_BUS_WIDTH_8;
+ if (pdata->port1_otg)
+ devflags |= ISP1760_FLAG_OTG_EN;
+ if (pdata->analog_oc)
+@@ -263,6 +273,7 @@ static int isp1760_plat_remove(struct platform_device *pdev)
+ static const struct of_device_id isp1760_of_match[] = {
+ { .compatible = "nxp,usb-isp1760", },
+ { .compatible = "nxp,usb-isp1761", },
++ { .compatible = "nxp,usb-isp1763", },
+ { },
+ };
+ MODULE_DEVICE_TABLE(of, isp1760_of_match);
+diff --git a/drivers/usb/isp1760/isp1760-regs.h b/drivers/usb/isp1760/isp1760-regs.h
+index 4e835e9665bd..313cb1fff1b3 100644
+--- a/drivers/usb/isp1760/isp1760-regs.h
++++ b/drivers/usb/isp1760/isp1760-regs.h
+@@ -19,8 +19,8 @@
+ * Host Controller
+ */
+
++/* ISP1760/31 */
+ /* EHCI capability registers */
+-#define ISP176x_HC_CAPLENGTH 0x000
+ #define ISP176x_HC_VERSION 0x002
+ #define ISP176x_HC_HCSPARAMS 0x004
+ #define ISP176x_HC_HCCPARAMS 0x008
+@@ -61,11 +61,13 @@
+ #define ISP176x_HC_INT_IRQ_MASK_AND 0x328
+ #define ISP176x_HC_ATL_IRQ_MASK_AND 0x32c
+
++#define ISP176x_HC_OTG_CTRL_SET 0x374
++#define ISP176x_HC_OTG_CTRL_CLEAR 0x376
+
+ static const struct regmap_range isp176x_hc_volatile_ranges[] = {
+ regmap_reg_range(ISP176x_HC_USBCMD, ISP176x_HC_ATL_PTD_LASTPTD),
+ regmap_reg_range(ISP176x_HC_BUFFER_STATUS, ISP176x_HC_MEMORY),
+- regmap_reg_range(ISP176x_HC_INTERRUPT, ISP176x_HC_ATL_IRQ_MASK_AND),
++ regmap_reg_range(ISP176x_HC_INTERRUPT, ISP176x_HC_OTG_CTRL_CLEAR),
+ };
+
+ static const struct regmap_access_table isp176x_hc_volatile_table = {
+@@ -74,6 +76,9 @@ static const struct regmap_access_table isp176x_hc_volatile_table = {
+ };
+
+ enum isp176x_host_controller_fields {
++ /* HC_PORTSC1 */
++ PORT_OWNER, PORT_POWER, PORT_LSTATUS, PORT_RESET, PORT_SUSPEND,
++ PORT_RESUME, PORT_PE, PORT_CSC, PORT_CONNECT,
+ /* HC_HCSPARAMS */
+ HCS_PPC, HCS_N_PORTS,
+ /* HC_HCCPARAMS */
+@@ -86,21 +91,40 @@ enum isp176x_host_controller_fields {
+ HC_FRINDEX,
+ /* HC_CONFIGFLAG */
+ FLAG_CF,
+- /* HC_PORTSC1 */
+- PORT_OWNER, PORT_POWER, PORT_LSTATUS, PORT_RESET, PORT_SUSPEND,
+- PORT_RESUME, PORT_PE, PORT_CSC, PORT_CONNECT,
++ /* ISO/INT/ATL PTD */
++ HC_ISO_PTD_DONEMAP, HC_ISO_PTD_SKIPMAP, HC_ISO_PTD_LASTPTD,
++ HC_INT_PTD_DONEMAP, HC_INT_PTD_SKIPMAP, HC_INT_PTD_LASTPTD,
++ HC_ATL_PTD_DONEMAP, HC_ATL_PTD_SKIPMAP, HC_ATL_PTD_LASTPTD,
+ /* HC_HW_MODE_CTRL */
+ ALL_ATX_RESET, HW_ANA_DIGI_OC, HW_DEV_DMA, HW_COMN_IRQ, HW_COMN_DMA,
+ HW_DATA_BUS_WIDTH, HW_DACK_POL_HIGH, HW_DREQ_POL_HIGH, HW_INTR_HIGH_ACT,
+- HW_INTR_EDGE_TRIG, HW_GLOBAL_INTR_EN,
++ HW_INTF_LOCK, HW_INTR_EDGE_TRIG, HW_GLOBAL_INTR_EN,
++ /* HC_CHIP_ID */
++ HC_CHIP_ID_HIGH, HC_CHIP_ID_LOW, HC_CHIP_REV,
++ /* HC_SCRATCH */
++ HC_SCRATCH,
+ /* HC_RESET */
+- SW_RESET_RESET_HC, SW_RESET_RESET_ALL,
++ SW_RESET_RESET_ATX, SW_RESET_RESET_HC, SW_RESET_RESET_ALL,
+ /* HC_BUFFER_STATUS */
+- INT_BUF_FILL, ATL_BUF_FILL,
++ ISO_BUF_FILL, INT_BUF_FILL, ATL_BUF_FILL,
+ /* HC_MEMORY */
+ MEM_BANK_SEL, MEM_START_ADDR,
++ /* HC_DATA */
++ HC_DATA,
++ /* HC_INTERRUPT */
++ HC_INTERRUPT,
+ /* HC_INTERRUPT_ENABLE */
+- HC_INT_ENABLE,
++ HC_INT_IRQ_ENABLE, HC_ATL_IRQ_ENABLE,
++ /* INTERRUPT MASKS */
++ HC_ISO_IRQ_MASK_OR, HC_INT_IRQ_MASK_OR, HC_ATL_IRQ_MASK_OR,
++ HC_ISO_IRQ_MASK_AND, HC_INT_IRQ_MASK_AND, HC_ATL_IRQ_MASK_AND,
++ /* HW_OTG_CTRL_SET */
++ HW_OTG_DISABLE, HW_SW_SEL_HC_DC, HW_VBUS_DRV, HW_SEL_CP_EXT,
++ HW_DM_PULLDOWN, HW_DP_PULLDOWN, HW_DP_PULLUP, HW_HC_2_DIS,
++ /* HW_OTG_CTRL_CLR */
++ HW_OTG_DISABLE_CLEAR, HW_SW_SEL_HC_DC_CLEAR, HW_VBUS_DRV_CLEAR,
++ HW_SEL_CP_EXT_CLEAR, HW_DM_PULLDOWN_CLEAR, HW_DP_PULLDOWN_CLEAR,
++ HW_DP_PULLUP_CLEAR, HW_HC_2_DIS_CLEAR,
+ /* Last element */
+ HC_FIELD_MAX,
+ };
+@@ -116,6 +140,15 @@ static const struct reg_field isp1760_hc_reg_fields[] = {
+ [STS_PCD] = REG_FIELD(ISP176x_HC_USBSTS, 2, 2),
+ [HC_FRINDEX] = REG_FIELD(ISP176x_HC_FRINDEX, 0, 13),
+ [FLAG_CF] = REG_FIELD(ISP176x_HC_CONFIGFLAG, 0, 0),
++ [HC_ISO_PTD_DONEMAP] = REG_FIELD(ISP176x_HC_ISO_PTD_DONEMAP, 0, 31),
++ [HC_ISO_PTD_SKIPMAP] = REG_FIELD(ISP176x_HC_ISO_PTD_SKIPMAP, 0, 31),
++ [HC_ISO_PTD_LASTPTD] = REG_FIELD(ISP176x_HC_ISO_PTD_LASTPTD, 0, 31),
++ [HC_INT_PTD_DONEMAP] = REG_FIELD(ISP176x_HC_INT_PTD_DONEMAP, 0, 31),
++ [HC_INT_PTD_SKIPMAP] = REG_FIELD(ISP176x_HC_INT_PTD_SKIPMAP, 0, 31),
++ [HC_INT_PTD_LASTPTD] = REG_FIELD(ISP176x_HC_INT_PTD_LASTPTD, 0, 31),
++ [HC_ATL_PTD_DONEMAP] = REG_FIELD(ISP176x_HC_ATL_PTD_DONEMAP, 0, 31),
++ [HC_ATL_PTD_SKIPMAP] = REG_FIELD(ISP176x_HC_ATL_PTD_SKIPMAP, 0, 31),
++ [HC_ATL_PTD_LASTPTD] = REG_FIELD(ISP176x_HC_ATL_PTD_LASTPTD, 0, 31),
+ [PORT_OWNER] = REG_FIELD(ISP176x_HC_PORTSC1, 13, 13),
+ [PORT_POWER] = REG_FIELD(ISP176x_HC_PORTSC1, 12, 12),
+ [PORT_LSTATUS] = REG_FIELD(ISP176x_HC_PORTSC1, 10, 11),
+@@ -134,12 +167,174 @@ static const struct reg_field isp1760_hc_reg_fields[] = {
+ [HW_INTR_HIGH_ACT] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 2, 2),
+ [HW_INTR_EDGE_TRIG] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 1, 1),
+ [HW_GLOBAL_INTR_EN] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 0, 0),
++ [HC_CHIP_REV] = REG_FIELD(ISP176x_HC_CHIP_ID, 16, 31),
++ [HC_CHIP_ID_HIGH] = REG_FIELD(ISP176x_HC_CHIP_ID, 8, 15),
++ [HC_CHIP_ID_LOW] = REG_FIELD(ISP176x_HC_CHIP_ID, 0, 7),
++ [HC_SCRATCH] = REG_FIELD(ISP176x_HC_SCRATCH, 0, 31),
+ [SW_RESET_RESET_ALL] = REG_FIELD(ISP176x_HC_RESET, 0, 0),
++ [ISO_BUF_FILL] = REG_FIELD(ISP176x_HC_BUFFER_STATUS, 2, 2),
+ [INT_BUF_FILL] = REG_FIELD(ISP176x_HC_BUFFER_STATUS, 1, 1),
+ [ATL_BUF_FILL] = REG_FIELD(ISP176x_HC_BUFFER_STATUS, 0, 0),
+ [MEM_BANK_SEL] = REG_FIELD(ISP176x_HC_MEMORY, 16, 17),
+ [MEM_START_ADDR] = REG_FIELD(ISP176x_HC_MEMORY, 0, 15),
+- [HC_INT_ENABLE] = REG_FIELD(ISP176x_HC_INTERRUPT_ENABLE, 7, 8),
++ [HC_INTERRUPT] = REG_FIELD(ISP176x_HC_INTERRUPT, 0, 9),
++ [HC_ATL_IRQ_ENABLE] = REG_FIELD(ISP176x_HC_INTERRUPT_ENABLE, 8, 8),
++ [HC_INT_IRQ_ENABLE] = REG_FIELD(ISP176x_HC_INTERRUPT_ENABLE, 7, 7),
++ [HC_ISO_IRQ_MASK_OR] = REG_FIELD(ISP176x_HC_ISO_IRQ_MASK_OR, 0, 31),
++ [HC_INT_IRQ_MASK_OR] = REG_FIELD(ISP176x_HC_INT_IRQ_MASK_OR, 0, 31),
++ [HC_ATL_IRQ_MASK_OR] = REG_FIELD(ISP176x_HC_ATL_IRQ_MASK_OR, 0, 31),
++ [HC_ISO_IRQ_MASK_AND] = REG_FIELD(ISP176x_HC_ISO_IRQ_MASK_AND, 0, 31),
++ [HC_INT_IRQ_MASK_AND] = REG_FIELD(ISP176x_HC_INT_IRQ_MASK_AND, 0, 31),
++ [HC_ATL_IRQ_MASK_AND] = REG_FIELD(ISP176x_HC_ATL_IRQ_MASK_AND, 0, 31),
++ [HW_OTG_DISABLE] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 10, 10),
++ [HW_SW_SEL_HC_DC] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 7, 7),
++ [HW_VBUS_DRV] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 4, 4),
++ [HW_SEL_CP_EXT] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 3, 3),
++ [HW_DM_PULLDOWN] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 2, 2),
++ [HW_DP_PULLDOWN] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 1, 1),
++ [HW_DP_PULLUP] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 0, 0),
++ [HW_OTG_DISABLE_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 10, 10),
++ [HW_SW_SEL_HC_DC_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 7, 7),
++ [HW_VBUS_DRV_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 4, 4),
++ [HW_SEL_CP_EXT_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 3, 3),
++ [HW_DM_PULLDOWN_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 2, 2),
++ [HW_DP_PULLDOWN_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 1, 1),
++ [HW_DP_PULLUP_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 0, 0),
++};
++
++/* ISP1763 */
++/* EHCI operational registers */
++#define ISP1763_HC_USBCMD 0x8c
++#define ISP1763_HC_USBSTS 0x90
++#define ISP1763_HC_FRINDEX 0x98
++
++#define ISP1763_HC_CONFIGFLAG 0x9c
++#define ISP1763_HC_PORTSC1 0xa0
++
++#define ISP1763_HC_ISO_PTD_DONEMAP 0xa4
++#define ISP1763_HC_ISO_PTD_SKIPMAP 0xa6
++#define ISP1763_HC_ISO_PTD_LASTPTD 0xa8
++#define ISP1763_HC_INT_PTD_DONEMAP 0xaa
++#define ISP1763_HC_INT_PTD_SKIPMAP 0xac
++#define ISP1763_HC_INT_PTD_LASTPTD 0xae
++#define ISP1763_HC_ATL_PTD_DONEMAP 0xb0
++#define ISP1763_HC_ATL_PTD_SKIPMAP 0xb2
++#define ISP1763_HC_ATL_PTD_LASTPTD 0xb4
++
++/* Configuration Register */
++#define ISP1763_HC_HW_MODE_CTRL 0xb6
++#define ISP1763_HC_CHIP_REV 0x70
++#define ISP1763_HC_CHIP_ID 0x72
++#define ISP1763_HC_SCRATCH 0x78
++#define ISP1763_HC_RESET 0xb8
++#define ISP1763_HC_BUFFER_STATUS 0xba
++#define ISP1763_HC_MEMORY 0xc4
++#define ISP1763_HC_DATA 0xc6
++
++/* Interrupt Register */
++#define ISP1763_HC_INTERRUPT 0xd4
++#define ISP1763_HC_INTERRUPT_ENABLE 0xd6
++#define ISP1763_HC_ISO_IRQ_MASK_OR 0xd8
++#define ISP1763_HC_INT_IRQ_MASK_OR 0xda
++#define ISP1763_HC_ATL_IRQ_MASK_OR 0xdc
++#define ISP1763_HC_ISO_IRQ_MASK_AND 0xde
++#define ISP1763_HC_INT_IRQ_MASK_AND 0xe0
++#define ISP1763_HC_ATL_IRQ_MASK_AND 0xe2
++
++#define ISP1763_HC_OTG_CTRL_SET 0xe4
++#define ISP1763_HC_OTG_CTRL_CLEAR 0xe6
++
++static const struct reg_field isp1763_hc_reg_fields[] = {
++ [CMD_LRESET] = REG_FIELD(ISP1763_HC_USBCMD, 7, 7),
++ [CMD_RESET] = REG_FIELD(ISP1763_HC_USBCMD, 1, 1),
++ [CMD_RUN] = REG_FIELD(ISP1763_HC_USBCMD, 0, 0),
++ [STS_PCD] = REG_FIELD(ISP1763_HC_USBSTS, 2, 2),
++ [HC_FRINDEX] = REG_FIELD(ISP1763_HC_FRINDEX, 0, 13),
++ [FLAG_CF] = REG_FIELD(ISP1763_HC_CONFIGFLAG, 0, 0),
++ [HC_ISO_PTD_DONEMAP] = REG_FIELD(ISP1763_HC_ISO_PTD_DONEMAP, 0, 15),
++ [HC_ISO_PTD_SKIPMAP] = REG_FIELD(ISP1763_HC_ISO_PTD_SKIPMAP, 0, 15),
++ [HC_ISO_PTD_LASTPTD] = REG_FIELD(ISP1763_HC_ISO_PTD_LASTPTD, 0, 15),
++ [HC_INT_PTD_DONEMAP] = REG_FIELD(ISP1763_HC_INT_PTD_DONEMAP, 0, 15),
++ [HC_INT_PTD_SKIPMAP] = REG_FIELD(ISP1763_HC_INT_PTD_SKIPMAP, 0, 15),
++ [HC_INT_PTD_LASTPTD] = REG_FIELD(ISP1763_HC_INT_PTD_LASTPTD, 0, 15),
++ [HC_ATL_PTD_DONEMAP] = REG_FIELD(ISP1763_HC_ATL_PTD_DONEMAP, 0, 15),
++ [HC_ATL_PTD_SKIPMAP] = REG_FIELD(ISP1763_HC_ATL_PTD_SKIPMAP, 0, 15),
++ [HC_ATL_PTD_LASTPTD] = REG_FIELD(ISP1763_HC_ATL_PTD_LASTPTD, 0, 15),
++ [PORT_OWNER] = REG_FIELD(ISP1763_HC_PORTSC1, 13, 13),
++ [PORT_POWER] = REG_FIELD(ISP1763_HC_PORTSC1, 12, 12),
++ [PORT_LSTATUS] = REG_FIELD(ISP1763_HC_PORTSC1, 10, 11),
++ [PORT_RESET] = REG_FIELD(ISP1763_HC_PORTSC1, 8, 8),
++ [PORT_SUSPEND] = REG_FIELD(ISP1763_HC_PORTSC1, 7, 7),
++ [PORT_RESUME] = REG_FIELD(ISP1763_HC_PORTSC1, 6, 6),
++ [PORT_PE] = REG_FIELD(ISP1763_HC_PORTSC1, 2, 2),
++ [PORT_CSC] = REG_FIELD(ISP1763_HC_PORTSC1, 1, 1),
++ [PORT_CONNECT] = REG_FIELD(ISP1763_HC_PORTSC1, 0, 0),
++ [HW_DATA_BUS_WIDTH] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 4, 4),
++ [HW_DACK_POL_HIGH] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 6, 6),
++ [HW_DREQ_POL_HIGH] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 5, 5),
++ [HW_INTF_LOCK] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 3, 3),
++ [HW_INTR_HIGH_ACT] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 2, 2),
++ [HW_INTR_EDGE_TRIG] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 1, 1),
++ [HW_GLOBAL_INTR_EN] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 0, 0),
++ [SW_RESET_RESET_ATX] = REG_FIELD(ISP1763_HC_RESET, 3, 3),
++ [SW_RESET_RESET_ALL] = REG_FIELD(ISP1763_HC_RESET, 0, 0),
++ [HC_CHIP_ID_HIGH] = REG_FIELD(ISP1763_HC_CHIP_ID, 0, 15),
++ [HC_CHIP_ID_LOW] = REG_FIELD(ISP1763_HC_CHIP_REV, 8, 15),
++ [HC_CHIP_REV] = REG_FIELD(ISP1763_HC_CHIP_REV, 0, 7),
++ [HC_SCRATCH] = REG_FIELD(ISP1763_HC_SCRATCH, 0, 15),
++ [ISO_BUF_FILL] = REG_FIELD(ISP1763_HC_BUFFER_STATUS, 2, 2),
++ [INT_BUF_FILL] = REG_FIELD(ISP1763_HC_BUFFER_STATUS, 1, 1),
++ [ATL_BUF_FILL] = REG_FIELD(ISP1763_HC_BUFFER_STATUS, 0, 0),
++ [MEM_START_ADDR] = REG_FIELD(ISP1763_HC_MEMORY, 0, 15),
++ [HC_DATA] = REG_FIELD(ISP1763_HC_DATA, 0, 15),
++ [HC_INTERRUPT] = REG_FIELD(ISP1763_HC_INTERRUPT, 0, 10),
++ [HC_ATL_IRQ_ENABLE] = REG_FIELD(ISP1763_HC_INTERRUPT_ENABLE, 8, 8),
++ [HC_INT_IRQ_ENABLE] = REG_FIELD(ISP1763_HC_INTERRUPT_ENABLE, 7, 7),
++ [HC_ISO_IRQ_MASK_OR] = REG_FIELD(ISP1763_HC_ISO_IRQ_MASK_OR, 0, 15),
++ [HC_INT_IRQ_MASK_OR] = REG_FIELD(ISP1763_HC_INT_IRQ_MASK_OR, 0, 15),
++ [HC_ATL_IRQ_MASK_OR] = REG_FIELD(ISP1763_HC_ATL_IRQ_MASK_OR, 0, 15),
++ [HC_ISO_IRQ_MASK_AND] = REG_FIELD(ISP1763_HC_ISO_IRQ_MASK_AND, 0, 15),
++ [HC_INT_IRQ_MASK_AND] = REG_FIELD(ISP1763_HC_INT_IRQ_MASK_AND, 0, 15),
++ [HC_ATL_IRQ_MASK_AND] = REG_FIELD(ISP1763_HC_ATL_IRQ_MASK_AND, 0, 15),
++ [HW_HC_2_DIS] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 15, 15),
++ [HW_OTG_DISABLE] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 10, 10),
++ [HW_SW_SEL_HC_DC] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 7, 7),
++ [HW_VBUS_DRV] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 4, 4),
++ [HW_SEL_CP_EXT] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 3, 3),
++ [HW_DM_PULLDOWN] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 2, 2),
++ [HW_DP_PULLDOWN] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 1, 1),
++ [HW_DP_PULLUP] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 0, 0),
++ [HW_HC_2_DIS_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 15, 15),
++ [HW_OTG_DISABLE_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 10, 10),
++ [HW_SW_SEL_HC_DC_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 7, 7),
++ [HW_VBUS_DRV_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 4, 4),
++ [HW_SEL_CP_EXT_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 3, 3),
++ [HW_DM_PULLDOWN_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 2, 2),
++ [HW_DP_PULLDOWN_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 1, 1),
++ [HW_DP_PULLUP_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 0, 0),
++};
++
++static const struct regmap_range isp1763_hc_volatile_ranges[] = {
++ regmap_reg_range(ISP1763_HC_USBCMD, ISP1763_HC_ATL_PTD_LASTPTD),
++ regmap_reg_range(ISP1763_HC_BUFFER_STATUS, ISP1763_HC_DATA),
++ regmap_reg_range(ISP1763_HC_INTERRUPT, ISP1763_HC_OTG_CTRL_CLEAR),
++};
++
++static const struct regmap_access_table isp1763_hc_volatile_table = {
++ .yes_ranges = isp1763_hc_volatile_ranges,
++ .n_yes_ranges = ARRAY_SIZE(isp1763_hc_volatile_ranges),
++};
++
++static const u32 isp1763_hc_portsc1_fields[] = {
++ [PORT_OWNER] = BIT(13),
++ [PORT_POWER] = BIT(12),
++ [PORT_LSTATUS] = BIT(10),
++ [PORT_RESET] = BIT(8),
++ [PORT_SUSPEND] = BIT(7),
++ [PORT_RESUME] = BIT(6),
++ [PORT_PE] = BIT(2),
++ [PORT_CSC] = BIT(1),
++ [PORT_CONNECT] = BIT(0),
+ };
+
+ /* -----------------------------------------------------------------------------
+@@ -172,9 +367,6 @@ static const struct reg_field isp1760_hc_reg_fields[] = {
+ #define ISP176x_DC_CTRLFUNC 0x0228
+ #define ISP176x_DC_EPINDEX 0x022c
+
+-#define ISP1761_DC_OTG_CTRL_SET 0x374
+-#define ISP1761_DC_OTG_CTRL_CLEAR 0x376
+-
+ /* DMA Registers */
+ #define ISP176x_DC_DMACMD 0x0230
+ #define ISP176x_DC_DMATXCOUNT 0x0234
+@@ -197,7 +389,6 @@ static const struct reg_field isp1760_hc_reg_fields[] = {
+ static const struct regmap_range isp176x_dc_volatile_ranges[] = {
+ regmap_reg_range(ISP176x_DC_EPMAXPKTSZ, ISP176x_DC_EPTYPE),
+ regmap_reg_range(ISP176x_DC_BUFLEN, ISP176x_DC_EPINDEX),
+- regmap_reg_range(ISP1761_DC_OTG_CTRL_SET, ISP1761_DC_OTG_CTRL_CLEAR),
+ };
+
+ static const struct regmap_access_table isp176x_dc_volatile_table = {
+@@ -228,13 +419,6 @@ enum isp176x_device_controller_fields {
+ DC_EPENABLE, DC_ENDPTYP,
+ /* DC_FRAMENUM */
+ DC_FRAMENUM, DC_UFRAMENUM,
+- /* HW_OTG_CTRL_SET */
+- HW_OTG_DISABLE, HW_SW_SEL_HC_DC, HW_VBUS_DRV, HW_SEL_CP_EXT,
+- HW_DM_PULLDOWN, HW_DP_PULLDOWN, HW_DP_PULLUP,
+- /* HW_OTG_CTRL_CLR */
+- HW_OTG_DISABLE_CLEAR, HW_SW_SEL_HC_DC_CLEAR, HW_VBUS_DRV_CLEAR,
+- HW_SEL_CP_EXT_CLEAR, HW_DM_PULLDOWN_CLEAR, HW_DP_PULLDOWN_CLEAR,
+- HW_DP_PULLUP_CLEAR,
+ /* Last element */
+ DC_FIELD_MAX,
+ };
+@@ -277,20 +461,6 @@ static const struct reg_field isp1761_dc_reg_fields[] = {
+ [DC_ENDPTYP] = REG_FIELD(ISP176x_DC_EPTYPE, 0, 1),
+ [DC_UFRAMENUM] = REG_FIELD(ISP176x_DC_FRAMENUM, 11, 13),
+ [DC_FRAMENUM] = REG_FIELD(ISP176x_DC_FRAMENUM, 0, 10),
+- [HW_OTG_DISABLE] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 10, 10),
+- [HW_SW_SEL_HC_DC] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 7, 7),
+- [HW_VBUS_DRV] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 4, 4),
+- [HW_SEL_CP_EXT] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 3, 3),
+- [HW_DM_PULLDOWN] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 2, 2),
+- [HW_DP_PULLDOWN] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 1, 1),
+- [HW_DP_PULLUP] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 0, 0),
+- [HW_OTG_DISABLE] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 10, 10),
+- [HW_SW_SEL_HC_DC] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 7, 7),
+- [HW_VBUS_DRV] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 4, 4),
+- [HW_SEL_CP_EXT] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 3, 3),
+- [HW_DM_PULLDOWN] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 2, 2),
+- [HW_DP_PULLDOWN] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 1, 1),
+- [HW_DP_PULLUP] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 0, 0),
+ };
+
+ #endif
+diff --git a/include/linux/usb/isp1760.h b/include/linux/usb/isp1760.h
+index b75ded28db81..84c8ca9d5b90 100644
+--- a/include/linux/usb/isp1760.h
++++ b/include/linux/usb/isp1760.h
+@@ -9,7 +9,9 @@
+
+ struct isp1760_platform_data {
+ unsigned is_isp1761:1; /* Chip is ISP1761 */
++ unsigned is_isp1763:1; /* Chip is ISP1763 */
+ unsigned bus_width_16:1; /* 16/32-bit data bus width */
++ unsigned bus_width_8:1; /* 8/16-bit data bus width */
+ unsigned port1_otg:1; /* Port 1 supports OTG */
+ unsigned analog_oc:1; /* Analog overcurrent */
+ unsigned dack_polarity_high:1; /* DACK active high */
+--
+2.17.1
+
new file mode 100644
@@ -0,0 +1,54 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/files/corstone700:"
+
+# including linux-yocto.inc to use configuration fragments
+require recipes-kernel/linux/linux-yocto.inc
+
+LINUX_VMAJOR = "5"
+LINUX_VMINOR = "6"
+LINUX_VPATCH = "14"
+LINUX_SRCREV = "e3ac9117b18596b7363d5b7904ab03a7d782b40c"
+
+COMPATIBLE_MACHINE = "${MACHINE}"
+
+KMACHINE = "corstone700"
+
+SRC_URI += " \
+ file://0001-arm-support-for-a-single-ARMv7-A-based-platform.patch \
+ file://0002-arm-Add-tiny-vexpress-machine.patch \
+ file://0003-arm-introduce-corstone700_defconfig.patch \
+ file://0004-add-driver-of-mailbox-handling-unit-controller-versi.patch \
+ file://0005-add-rpmsg-based-on-rpmsg-char-driver-using-mailbox.patch \
+ file://0006-enable-arm-MHU-driver-and-RPMSG-char-driver.patch \
+ file://0007-allow-creation-of-multiple-arm-rpmsg-channels.patch \
+ file://0008-mailbox-enable-combined-receiver-interrupt-when-usin.patch \
+ file://0009-misc-arm-add-corstone700-external-system-harness-dri.patch \
+ file://0010-arm-containerize-endpoint-and-mailbox-information.patch \
+ file://0011-arm-couple-mailbox-channel-ownership-to-rpmsg-endpoi.patch \
+ file://0012-mailbox-arm_mhu_v2-add-new-AMBA-ID-to-support-MHU-v2.patch \
+ file://0013-mailbox-arm_mhu_v2-dynamic-allocation-of-channels.patch \
+ file://0014-defconfig-adjust-XIP-physical-address-to-3MB-offset.patch \
+ file://0015-arm-Kconfig-disable-ARM_VIRT-extension-if-XIP_KERNEL.patch \
+ file://0016-corstone700_defconfig-use-DDR-address-instead-of-sha.patch \
+ file://0017-corstone700_defconfig-enable-configs-for-cramfs-xip.patch \
+ file://0018-usb-isp1760-move-to-regmap-for-register-access.patch \
+ file://0019-usb-isp1760-hcd-refactor-mempool-config-and-setup.patch \
+ file://0020-usb-isp1760-add-support-for-isp1763.patch \
+ "
+
+KERNEL_IMAGETYPE = "xipImage"
+
+KCONFIG_MODE = "--alldefconfig"
+
+KMETA = "arm-platforms-kmeta"
+SRC_URI_append = " ${SRC_URI_KMETA}"
+
+KERNEL_EXTRA_FEATURES = "bsp/arm-platforms/corstone700-bsp.scc"
+KERNEL_FEATURES_append = " ${KERNEL_EXTRA_FEATURES}"
+
+KERNEL_FEATURES_append_corstone700-fvp = " \
+ ${@bb.utils.contains('MACHINE_FEATURES', \
+ 'eth_lan91c111', \
+ 'bsp/arm-platforms/corstone700/xip_dhcp_cmdline.cfg \
+ bsp/arm-platforms/corstone700/eth_lan91c111.scc', \
+ 'bsp/arm-platforms/corstone700/xip_cmdline.cfg', \
+ d)}"
@@ -1,3 +1,11 @@
# Add support for Arm Platforms (boards or simulators)
require linux-arm-platforms.inc
+
+#
+# Corstone700 KMACHINE
+#
+MACHINE_KERNEL_REQUIRE ?= ""
+MACHINE_KERNEL_REQUIRE_corstone700 = "linux-stable-corstone700.inc"
+
+require ${MACHINE_KERNEL_REQUIRE}