Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/shli/md
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 29 Jul 2016 01:04:39 +0000 (18:04 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 29 Jul 2016 01:04:39 +0000 (18:04 -0700)
Pull MD updates from Shaohua Li:
 - A bunch of patches from Neil Brown to fix RCU usage
 - Two performance improvement patches from Tomasz Majchrzak
 - Alexey Obitotskiy fixes module refcount issue
 - Arnd Bergmann fixes time granularity
 - Cong Wang fixes a list corruption issue
 - Guoqing Jiang fixes a deadlock in md-cluster
 - A null pointer deference fix from me
 - Song Liu fixes misuse of raid6 rmw
 - Other trival/cleanup fixes from Guoqing Jiang and Xiao Ni

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/shli/md: (28 commits)
  MD: fix null pointer deference
  raid10: improve random reads performance
  md: add missing sysfs_notify on array_state update
  Fix kernel module refcount handling
  md: use seconds granularity for error logging
  md: reduce the number of synchronize_rcu() calls when multiple devices fail.
  md: be extra careful not to take a reference to a Faulty device.
  md/multipath: add rcu protection to rdev access in multipath_status.
  md/raid5: add rcu protection to rdev accesses in raid5_status.
  md/raid5: add rcu protection to rdev accesses in want_replace
  md/raid5: add rcu protection to rdev accesses in handle_failed_sync.
  md/raid1: add rcu protection to rdev in fix_read_error
  md/raid1: small code cleanup in end_sync_write
  md/raid1: small cleanup in raid1_end_read/write_request
  md/raid10: simplify print_conf a little.
  md/raid10: minor code improvement in fix_read_error()
  md/raid10: add rcu protection to rdev access during reshape.
  md/raid10: add rcu protection to rdev access in raid10_sync_request.
  md/raid10: add rcu protection in raid10_status.
  md/raid10: fix refounct imbalance when resyncing an array with a replacement device.
  ...

458 files changed:
Documentation/block/biodoc.txt
Documentation/cgroup-v1/memcg_test.txt
Documentation/cgroup-v1/memory.txt
Documentation/devicetree/bindings/dma/mv-xor-v2.txt [new file with mode: 0644]
Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt
Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt [deleted file]
Documentation/devicetree/bindings/dma/xilinx/zynqmp_dma.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio_oxnas.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/brcm,iproc-gpio.txt
Documentation/devicetree/bindings/pinctrl/brcm,nsp-pinmux.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/oxnas,pinctrl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/pinctrl-max77620.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/qcom,mdm9615-pinctrl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/qcom,msm8660-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt
Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt
Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt [new file with mode: 0644]
Documentation/filesystems/Locking
Documentation/filesystems/vfs.txt
Documentation/hid/hid-alps.txt [new file with mode: 0644]
Documentation/nvdimm/btt.txt
Documentation/pinctrl.txt
MAINTAINERS
arch/arm/include/asm/io.h
arch/arm64/mm/init.c
arch/powerpc/sysdev/axonram.c
arch/s390/appldata/appldata_mem.c
arch/tile/mm/pgtable.c
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/pmem.h
arch/x86/include/asm/special_insns.h
arch/x86/include/asm/vmx.h
arch/x86/include/uapi/asm/vmx.h
arch/x86/kvm/cpuid.c
arch/x86/kvm/cpuid.h
arch/x86/kvm/vmx.c
arch/x86/lib/x86-opcode-map.txt
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/nfit.c [deleted file]
drivers/acpi/nfit.h [deleted file]
drivers/acpi/nfit/Kconfig [new file with mode: 0644]
drivers/acpi/nfit/Makefile [new file with mode: 0644]
drivers/acpi/nfit/core.c [new file with mode: 0644]
drivers/acpi/nfit/mce.c [new file with mode: 0644]
drivers/acpi/nfit/nfit.h [new file with mode: 0644]
drivers/base/node.c
drivers/block/brd.c
drivers/block/drbd/drbd_debugfs.c
drivers/char/random.c
drivers/dax/dax.c
drivers/dax/pmem.c
drivers/dma/Kconfig
drivers/dma/Makefile
drivers/dma/amba-pl08x.c
drivers/dma/at_xdmac.c
drivers/dma/bcm2835-dma.c
drivers/dma/bestcomm/bestcomm.c
drivers/dma/coh901318.c
drivers/dma/cppi41.c
drivers/dma/dma-axi-dmac.c
drivers/dma/dma-jz4740.c
drivers/dma/dmatest.c
drivers/dma/edma.c
drivers/dma/fsl-edma.c
drivers/dma/fsl_raid.c
drivers/dma/fsldma.c
drivers/dma/imx-dma.c
drivers/dma/imx-sdma.c
drivers/dma/ioat/init.c
drivers/dma/k3dma.c
drivers/dma/mmp_pdma.c
drivers/dma/mmp_tdma.c
drivers/dma/moxart-dma.c
drivers/dma/mpc512x_dma.c
drivers/dma/mv_xor.c
drivers/dma/mv_xor_v2.c [new file with mode: 0644]
drivers/dma/nbpfaxi.c
drivers/dma/omap-dma.c
drivers/dma/pl330.c
drivers/dma/ppc4xx/adma.c
drivers/dma/pxa_dma.c
drivers/dma/qcom/bam_dma.c
drivers/dma/qcom/hidma.c
drivers/dma/qcom/hidma_ll.c
drivers/dma/qcom/hidma_mgmt.c
drivers/dma/s3c24xx-dma.c
drivers/dma/sh/rcar-dmac.c
drivers/dma/sh/shdmac.c
drivers/dma/sh/sudmac.c
drivers/dma/sirf-dma.c
drivers/dma/ste_dma40.c
drivers/dma/ste_dma40_ll.c
drivers/dma/sun6i-dma.c
drivers/dma/tegra20-apb-dma.c
drivers/dma/ti-dma-crossbar.c
drivers/dma/timb_dma.c
drivers/dma/txx9dmac.c
drivers/dma/xilinx/Makefile
drivers/dma/xilinx/xilinx_dma.c [new file with mode: 0644]
drivers/dma/xilinx/xilinx_vdma.c [deleted file]
drivers/dma/xilinx/zynqmp_dma.c [new file with mode: 0644]
drivers/gpu/drm/armada/armada_gem.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/etnaviv/etnaviv_gem.c
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/omapdrm/omap_gem.c
drivers/gpu/drm/ttm/ttm_tt.c
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-alps.c [new file with mode: 0644]
drivers/hid/hid-apple.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-led.c [new file with mode: 0644]
drivers/hid/hid-thingm.c [deleted file]
drivers/hid/i2c-hid/i2c-hid.c
drivers/hid/uhid.c
drivers/hwspinlock/qcom_hwspinlock.c
drivers/md/dm-linear.c
drivers/md/dm-snap.c
drivers/md/dm-stripe.c
drivers/md/dm-target.c
drivers/md/dm.c
drivers/nvdimm/Kconfig
drivers/nvdimm/blk.c
drivers/nvdimm/btt_devs.c
drivers/nvdimm/bus.c
drivers/nvdimm/claim.c
drivers/nvdimm/core.c
drivers/nvdimm/dimm_devs.c
drivers/nvdimm/e820.c
drivers/nvdimm/nd-core.h
drivers/nvdimm/nd.h
drivers/nvdimm/pmem.c
drivers/nvdimm/pmem.h [new file with mode: 0644]
drivers/nvdimm/region.c
drivers/nvdimm/region_devs.c
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/bcm/Kconfig
drivers/pinctrl/bcm/Makefile
drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
drivers/pinctrl/bcm/pinctrl-ns2-mux.c
drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
drivers/pinctrl/bcm/pinctrl-nsp-mux.c [new file with mode: 0644]
drivers/pinctrl/core.c
drivers/pinctrl/core.h
drivers/pinctrl/devicetree.c
drivers/pinctrl/freescale/pinctrl-imx.c
drivers/pinctrl/freescale/pinctrl-imx1-core.c
drivers/pinctrl/freescale/pinctrl-imx1.c
drivers/pinctrl/freescale/pinctrl-imx21.c
drivers/pinctrl/freescale/pinctrl-imx23.c
drivers/pinctrl/freescale/pinctrl-imx25.c
drivers/pinctrl/freescale/pinctrl-imx27.c
drivers/pinctrl/freescale/pinctrl-imx28.c
drivers/pinctrl/freescale/pinctrl-imx35.c
drivers/pinctrl/freescale/pinctrl-imx50.c
drivers/pinctrl/freescale/pinctrl-imx51.c
drivers/pinctrl/freescale/pinctrl-imx53.c
drivers/pinctrl/freescale/pinctrl-imx6dl.c
drivers/pinctrl/freescale/pinctrl-imx6q.c
drivers/pinctrl/freescale/pinctrl-imx6sl.c
drivers/pinctrl/freescale/pinctrl-imx6sx.c
drivers/pinctrl/freescale/pinctrl-imx6ul.c
drivers/pinctrl/freescale/pinctrl-imx7d.c
drivers/pinctrl/freescale/pinctrl-mxs.c
drivers/pinctrl/freescale/pinctrl-mxs.h
drivers/pinctrl/freescale/pinctrl-vf610.c
drivers/pinctrl/intel/Kconfig
drivers/pinctrl/intel/Makefile
drivers/pinctrl/intel/pinctrl-baytrail.c
drivers/pinctrl/intel/pinctrl-broxton.c
drivers/pinctrl/intel/pinctrl-cherryview.c
drivers/pinctrl/intel/pinctrl-intel.c
drivers/pinctrl/intel/pinctrl-merrifield.c [new file with mode: 0644]
drivers/pinctrl/mediatek/pinctrl-mtk-common.c
drivers/pinctrl/meson/pinctrl-meson-gxbb.c
drivers/pinctrl/mvebu/pinctrl-kirkwood.c
drivers/pinctrl/nomadik/pinctrl-nomadik.c
drivers/pinctrl/pinconf-generic.c
drivers/pinctrl/pinconf.c
drivers/pinctrl/pinctrl-at91-pio4.c
drivers/pinctrl/pinctrl-at91.c
drivers/pinctrl/pinctrl-digicolor.c
drivers/pinctrl/pinctrl-lpc18xx.c
drivers/pinctrl/pinctrl-max77620.c [new file with mode: 0644]
drivers/pinctrl/pinctrl-oxnas.c [new file with mode: 0644]
drivers/pinctrl/pinctrl-rockchip.c
drivers/pinctrl/pinctrl-st.c
drivers/pinctrl/pinctrl-u300.c
drivers/pinctrl/pinctrl-xway.c
drivers/pinctrl/pinctrl-zynq.c
drivers/pinctrl/pinmux.c
drivers/pinctrl/qcom/Kconfig
drivers/pinctrl/qcom/Makefile
drivers/pinctrl/qcom/pinctrl-mdm9615.c [new file with mode: 0644]
drivers/pinctrl/qcom/pinctrl-msm.c
drivers/pinctrl/qcom/pinctrl-msm8660.c
drivers/pinctrl/qcom/pinctrl-msm8x74.c
drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c
drivers/pinctrl/samsung/pinctrl-exynos5440.c
drivers/pinctrl/samsung/pinctrl-samsung.c
drivers/pinctrl/sh-pfc/core.c
drivers/pinctrl/sh-pfc/core.h
drivers/pinctrl/sh-pfc/gpio.c
drivers/pinctrl/sh-pfc/pfc-r8a73a4.c
drivers/pinctrl/sh-pfc/pfc-r8a7740.c
drivers/pinctrl/sh-pfc/pfc-r8a7778.c
drivers/pinctrl/sh-pfc/pfc-r8a7790.c
drivers/pinctrl/sh-pfc/pfc-r8a7791.c
drivers/pinctrl/sh-pfc/pfc-r8a7795.c
drivers/pinctrl/sh-pfc/pfc-sh7757.c
drivers/pinctrl/sh-pfc/pinctrl.c
drivers/pinctrl/sh-pfc/sh_pfc.h
drivers/pinctrl/sirf/pinctrl-atlas7.c
drivers/pinctrl/stm32/Kconfig
drivers/pinctrl/stm32/Makefile
drivers/pinctrl/stm32/pinctrl-stm32.c
drivers/pinctrl/stm32/pinctrl-stm32f746.c [new file with mode: 0644]
drivers/pinctrl/sunxi/pinctrl-sun8i-a23.c
drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c
drivers/pinctrl/sunxi/pinctrl-sun8i-h3.c
drivers/pinctrl/tegra/pinctrl-tegra.c
drivers/pinctrl/tegra/pinctrl-tegra.h
drivers/pinctrl/tegra/pinctrl-tegra114.c
drivers/pinctrl/tegra/pinctrl-tegra124.c
drivers/pinctrl/tegra/pinctrl-tegra20.c
drivers/pinctrl/tegra/pinctrl-tegra210.c
drivers/pinctrl/tegra/pinctrl-tegra30.c
drivers/pinctrl/uniphier/Kconfig
drivers/pinctrl/uniphier/Makefile
drivers/pinctrl/uniphier/pinctrl-uniphier-core.c
drivers/pinctrl/uniphier/pinctrl-uniphier-ld11.c [new file with mode: 0644]
drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c [new file with mode: 0644]
drivers/pinctrl/uniphier/pinctrl-uniphier-ld4.c
drivers/pinctrl/uniphier/pinctrl-uniphier-ld6b.c
drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c
drivers/pinctrl/uniphier/pinctrl-uniphier-pro5.c
drivers/pinctrl/uniphier/pinctrl-uniphier-pxs2.c
drivers/pinctrl/uniphier/pinctrl-uniphier-sld8.c
drivers/pinctrl/uniphier/pinctrl-uniphier.h
drivers/remoteproc/Kconfig
drivers/remoteproc/Makefile
drivers/remoteproc/qcom_mdt_loader.c [new file with mode: 0644]
drivers/remoteproc/qcom_mdt_loader.h [new file with mode: 0644]
drivers/remoteproc/qcom_q6v5_pil.c [new file with mode: 0644]
drivers/remoteproc/remoteproc_core.c
drivers/s390/block/dcssblk.c
drivers/scsi/qla2xxx/qla_nx.h
drivers/staging/android/lowmemorykiller.c
drivers/staging/lustre/lustre/llite/statahead.c
drivers/staging/lustre/lustre/osc/osc_cache.c
drivers/usb/misc/Kconfig
drivers/usb/misc/Makefile
drivers/usb/misc/usbled.c [deleted file]
fs/9p/fid.h
fs/9p/vfs_addr.c
fs/9p/vfs_inode.c
fs/9p/vfs_inode_dotl.c
fs/adfs/dir.c
fs/affs/namei.c
fs/autofs4/waitq.c
fs/binfmt_misc.c
fs/block_dev.c
fs/cachefiles/proc.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/cifs/cifs_debug.c
fs/cifs/dir.c
fs/coda/pioctl.c
fs/dax.c
fs/dcache.c
fs/debugfs/inode.c
fs/efivarfs/super.c
fs/ext4/mballoc.c
fs/ext4/sysfs.c
fs/f2fs/super.c
fs/fat/inode.c
fs/fat/namei_msdos.c
fs/fat/namei_vfat.c
fs/fs-writeback.c
fs/fscache/histogram.c
fs/fscache/object-list.c
fs/fscache/stats.c
fs/fuse/dev.c
fs/fuse/dir.c
fs/fuse/file.c
fs/hfs/inode.c
fs/hfs/string.c
fs/hfsplus/inode.c
fs/hfsplus/unicode.c
fs/hpfs/dentry.c
fs/ioctl.c
fs/isofs/compress.c
fs/isofs/inode.c
fs/jffs2/dir.c
fs/jffs2/readinode.c
fs/jffs2/scan.c
fs/jffs2/summary.c
fs/jffs2/write.c
fs/jfs/jfs_debug.c
fs/jfs/jfs_logmgr.c
fs/jfs/jfs_metapage.c
fs/jfs/jfs_txnmgr.c
fs/jfs/jfs_xtree.c
fs/jfs/namei.c
fs/kernfs/dir.c
fs/lockd/procfs.c
fs/logfs/dir.c
fs/namei.c
fs/ncpfs/dir.c
fs/nfs/client.c
fs/nfs/dir.c
fs/nfs/direct.c
fs/nfs/internal.h
fs/nfs/write.c
fs/nfsd/nfsctl.c
fs/nfsd/stats.c
fs/ntfs/inode.c
fs/ntfs/namei.c
fs/ocfs2/aops.c
fs/ocfs2/dlm/dlmcommon.h
fs/ocfs2/quota_global.c
fs/ocfs2/xattr.c
fs/open.c
fs/orangefs/inode.c
fs/orangefs/namei.c
fs/orangefs/orangefs-kernel.h
fs/orangefs/symlink.c
fs/overlayfs/inode.c
fs/overlayfs/overlayfs.h
fs/overlayfs/super.c
fs/proc/base.c
fs/proc/meminfo.c
fs/proc/proc_sysctl.c
fs/quota/dquot.c
fs/sysv/namei.c
fs/tracefs/inode.c
fs/ufs/dir.c
fs/xfs/xfs_stats.c
include/dt-bindings/pinctrl/stm32f746-pinfunc.h [new file with mode: 0644]
include/linux/backing-dev.h
include/linux/blkdev.h
include/linux/compaction.h
include/linux/compiler.h
include/linux/dcache.h
include/linux/device-mapper.h
include/linux/fs.h
include/linux/fsnotify.h
include/linux/fsnotify_backend.h
include/linux/gfp.h
include/linux/huge_mm.h
include/linux/kasan.h
include/linux/kdb.h
include/linux/libnvdimm.h
include/linux/memblock.h
include/linux/memcontrol.h
include/linux/memremap.h
include/linux/mm.h
include/linux/mm_inline.h
include/linux/mm_types.h
include/linux/mmzone.h
include/linux/nd.h
include/linux/oom.h
include/linux/pfn_t.h
include/linux/pinctrl/pinconf-generic.h
include/linux/pmem.h
include/linux/quota.h
include/linux/sched.h
include/linux/slab_def.h
include/linux/slub_def.h
include/linux/stringhash.h
include/linux/sunrpc/svcauth.h
include/linux/swap.h
include/linux/topology.h
include/linux/vm_event_item.h
include/linux/vmstat.h
include/linux/writeback.h
include/trace/events/compaction.h
include/trace/events/mmflags.h
include/trace/events/vmscan.h
include/trace/events/writeback.h
include/uapi/linux/ndctl.h
init/Kconfig
kernel/cpuset.c
kernel/fork.c
kernel/freezer.c
kernel/memremap.c
kernel/power/snapshot.c
kernel/printk/printk.c
kernel/sysctl.c
lib/Kconfig.kasan
lib/iov_iter.c
lib/stackdepot.c
lib/test_hash.c
mm/Kconfig
mm/backing-dev.c
mm/compaction.c
mm/filemap.c
mm/huge_memory.c
mm/hugetlb.c
mm/internal.h
mm/kasan/Makefile
mm/kasan/kasan.c
mm/kasan/kasan.h
mm/kasan/report.c
mm/khugepaged.c
mm/kmemleak.c
mm/memblock.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory_hotplug.c
mm/mempolicy.c
mm/mempool.c
mm/migrate.c
mm/mlock.c
mm/mmap.c
mm/oom_kill.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_idle.c
mm/page_io.c
mm/rmap.c
mm/shmem.c
mm/slab.h
mm/slub.c
mm/sparse.c
mm/swap.c
mm/swap_state.c
mm/util.c
mm/vmscan.c
mm/vmstat.c
mm/workingset.c
mm/zsmalloc.c
net/core/dev.c
scripts/checkpatch.pl
security/inode.c
security/smack/smack_access.c
security/tomoyo/memory.c
security/tomoyo/util.c
sound/soc/codecs/max9877.h
tools/objtool/arch/x86/insn/x86-opcode-map.txt
tools/perf/arch/x86/tests/insn-x86-dat-32.c
tools/perf/arch/x86/tests/insn-x86-dat-64.c
tools/perf/arch/x86/tests/insn-x86-dat-src.c
tools/perf/builtin-kmem.c
tools/perf/util/intel-pt-decoder/x86-opcode-map.txt
tools/testing/nvdimm/Kbuild
tools/testing/nvdimm/config_check.c
tools/testing/nvdimm/pmem-dax.c [new file with mode: 0644]
tools/testing/nvdimm/test/Kbuild
tools/testing/nvdimm/test/iomap.c
tools/testing/nvdimm/test/nfit.c
tools/testing/nvdimm/test/nfit_test.h

index 5be8a7f..026d133 100644 (file)
@@ -1024,8 +1024,7 @@ could be on demand. For example wait_on_buffer sets the unplugging going
 through sync_buffer() running blk_run_address_space(mapping). Or the caller
 can do it explicity through blk_unplug(bdev). So in the read case,
 the queue gets explicitly unplugged as part of waiting for completion on that
-buffer. For page driven IO, the address space ->sync_page() takes care of
-doing the blk_run_address_space().
+buffer.
 
 Aside:
   This is kind of controversial territory, as it's not clear if plugging is
index 8870b02..78a8c29 100644 (file)
@@ -107,9 +107,9 @@ Under below explanation, we assume CONFIG_MEM_RES_CTRL_SWAP=y.
 
 8. LRU
         Each memcg has its own private LRU. Now, its handling is under global
-       VM's control (means that it's handled under global zone->lru_lock).
+       VM's control (means that it's handled under global zone_lru_lock).
        Almost all routines around memcg's LRU is called by global LRU's
-       list management functions under zone->lru_lock().
+       list management functions under zone_lru_lock().
 
        A special function is mem_cgroup_isolate_pages(). This scans
        memcg's private LRU and call __isolate_lru_page() to extract a page
index b14abf2..946e691 100644 (file)
@@ -267,11 +267,11 @@ When oom event notifier is registered, event will be delivered.
    Other lock order is following:
    PG_locked.
    mm->page_table_lock
-       zone->lru_lock
+       zone_lru_lock
          lock_page_cgroup.
   In many cases, just lock_page_cgroup() is called.
   per-zone-per-cgroup LRU (cgroup's private LRU) is just guarded by
-  zone->lru_lock, it has no lock of its own.
+  zone_lru_lock, it has no lock of its own.
 
 2.7 Kernel Memory Extension (CONFIG_MEMCG_KMEM)
 
diff --git a/Documentation/devicetree/bindings/dma/mv-xor-v2.txt b/Documentation/devicetree/bindings/dma/mv-xor-v2.txt
new file mode 100644 (file)
index 0000000..217a90e
--- /dev/null
@@ -0,0 +1,24 @@
+* Marvell XOR v2 engines
+
+Required properties:
+- compatible: one of the following values:
+    "marvell,armada-7k-xor"
+    "marvell,xor-v2"
+- reg: Should contain registers location and length (two sets)
+    the first set is the DMA registers
+    the second set is the global registers
+- msi-parent: Phandle to the MSI-capable interrupt controller used for
+  interrupts.
+
+Optional properties:
+- clocks: Optional reference to the clock used by the XOR engine.
+
+Example:
+
+       xor0@400000 {
+               compatible = "marvell,xor-v2";
+               reg = <0x400000 0x1000>,
+                     <0x410000 0x1000>;
+               msi-parent = <&gic_v2m0>;
+               dma-coherent;
+       };
index 3cf0072..a2b8bfa 100644 (file)
@@ -1,46 +1,96 @@
+Xilinx AXI VDMA engine, it does transfers between memory and video devices.
+It can be configured to have one channel or two channels. If configured
+as two channels, one is to transmit to the video device and another is
+to receive from the video device.
+
 Xilinx AXI DMA engine, it does transfers between memory and AXI4 stream
 target devices. It can be configured to have one channel or two channels.
 If configured as two channels, one is to transmit to the device and another
 is to receive from the device.
 
+Xilinx AXI CDMA engine, it does transfers between memory-mapped source
+address and a memory-mapped destination address.
+
 Required properties:
-- compatible: Should be "xlnx,axi-dma-1.00.a"
+- compatible: Should be "xlnx,axi-vdma-1.00.a" or "xlnx,axi-dma-1.00.a" or
+             "xlnx,axi-cdma-1.00.a""
 - #dma-cells: Should be <1>, see "dmas" property below
-- reg: Should contain DMA registers location and length.
+- reg: Should contain VDMA registers location and length.
+- xlnx,addrwidth: Should be the vdma addressing size in bits(ex: 32 bits).
+- dma-ranges: Should be as the following <dma_addr cpu_addr max_len>.
 - dma-channel child node: Should have at least one channel and can have up to
        two channels per device. This node specifies the properties of each
        DMA channel (see child node properties below).
+- clocks: Input clock specifier. Refer to common clock bindings.
+- clock-names: List of input clocks
+       For VDMA:
+       Required elements: "s_axi_lite_aclk"
+       Optional elements: "m_axi_mm2s_aclk" "m_axi_s2mm_aclk",
+                          "m_axis_mm2s_aclk", "s_axis_s2mm_aclk"
+       For CDMA:
+       Required elements: "s_axi_lite_aclk", "m_axi_aclk"
+       FOR AXIDMA:
+       Required elements: "s_axi_lite_aclk"
+       Optional elements: "m_axi_mm2s_aclk", "m_axi_s2mm_aclk",
+                          "m_axi_sg_aclk"
+
+Required properties for VDMA:
+- xlnx,num-fstores: Should be the number of framebuffers as configured in h/w.
 
 Optional properties:
-- xlnx,include-sg: Tells whether configured for Scatter-mode in
+- xlnx,include-sg: Tells configured for Scatter-mode in
        the hardware.
+Optional properties for AXI DMA:
+- xlnx,mcdma: Tells whether configured for multi-channel mode in the hardware.
+Optional properties for VDMA:
+- xlnx,flush-fsync: Tells which channel to Flush on Frame sync.
+       It takes following values:
+       {1}, flush both channels
+       {2}, flush mm2s channel
+       {3}, flush s2mm channel
 
 Required child node properties:
-- compatible: It should be either "xlnx,axi-dma-mm2s-channel" or
+- compatible:
+       For VDMA: It should be either "xlnx,axi-vdma-mm2s-channel" or
+       "xlnx,axi-vdma-s2mm-channel".
+       For CDMA: It should be "xlnx,axi-cdma-channel".
+       For AXIDMA: It should be either "xlnx,axi-dma-mm2s-channel" or
        "xlnx,axi-dma-s2mm-channel".
-- interrupts: Should contain per channel DMA interrupts.
+- interrupts: Should contain per channel VDMA interrupts.
 - xlnx,datawidth: Should contain the stream data width, take values
        {32,64...1024}.
 
-Option child node properties:
-- xlnx,include-dre: Tells whether hardware is configured for Data
+Optional child node properties:
+- xlnx,include-dre: Tells hardware is configured for Data
        Realignment Engine.
+Optional child node properties for VDMA:
+- xlnx,genlock-mode: Tells Genlock synchronization is
+       enabled/disabled in hardware.
+Optional child node properties for AXI DMA:
+-dma-channels: Number of dma channels in child node.
 
 Example:
 ++++++++
 
-axi_dma_0: axidma@40400000 {
-       compatible = "xlnx,axi-dma-1.00.a";
+axi_vdma_0: axivdma@40030000 {
+       compatible = "xlnx,axi-vdma-1.00.a";
        #dma_cells = <1>;
-       reg = < 0x40400000 0x10000 >;
-       dma-channel@40400000 {
-               compatible = "xlnx,axi-dma-mm2s-channel";
-               interrupts = < 0 59 4 >;
+       reg = < 0x40030000 0x10000 >;
+       dma-ranges = <0x00000000 0x00000000 0x40000000>;
+       xlnx,num-fstores = <0x8>;
+       xlnx,flush-fsync = <0x1>;
+       xlnx,addrwidth = <0x20>;
+       clocks = <&clk 0>, <&clk 1>, <&clk 2>, <&clk 3>, <&clk 4>;
+       clock-names = "s_axi_lite_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk",
+                     "m_axis_mm2s_aclk", "s_axis_s2mm_aclk";
+       dma-channel@40030000 {
+               compatible = "xlnx,axi-vdma-mm2s-channel";
+               interrupts = < 0 54 4 >;
                xlnx,datawidth = <0x40>;
        } ;
-       dma-channel@40400030 {
-               compatible = "xlnx,axi-dma-s2mm-channel";
-               interrupts = < 0 58 4 >;
+       dma-channel@40030030 {
+               compatible = "xlnx,axi-vdma-s2mm-channel";
+               interrupts = < 0 53 4 >;
                xlnx,datawidth = <0x40>;
        } ;
 } ;
@@ -49,7 +99,7 @@ axi_dma_0: axidma@40400000 {
 * DMA client
 
 Required properties:
-- dmas: a list of <[DMA device phandle] [Channel ID]> pairs,
+- dmas: a list of <[Video DMA device phandle] [Channel ID]> pairs,
        where Channel ID is '0' for write/tx and '1' for read/rx
        channel.
 - dma-names: a list of DMA channel names, one per "dmas" entry
@@ -57,9 +107,9 @@ Required properties:
 Example:
 ++++++++
 
-dmatest_0: dmatest@0 {
-       compatible ="xlnx,axi-dma-test-1.00.a";
-       dmas = <&axi_dma_0 0
-               &axi_dma_0 1>;
-       dma-names = "dma0", "dma1";
+vdmatest_0: vdmatest@0 {
+       compatible ="xlnx,axi-vdma-test-1.00.a";
+       dmas = <&axi_vdma_0 0
+               &axi_vdma_0 1>;
+       dma-names = "vdma0", "vdma1";
 } ;
diff --git a/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt b/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt
deleted file mode 100644 (file)
index a1f2683..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-Xilinx AXI VDMA engine, it does transfers between memory and video devices.
-It can be configured to have one channel or two channels. If configured
-as two channels, one is to transmit to the video device and another is
-to receive from the video device.
-
-Xilinx AXI DMA engine, it does transfers between memory and AXI4 stream
-target devices. It can be configured to have one channel or two channels.
-If configured as two channels, one is to transmit to the device and another
-is to receive from the device.
-
-Xilinx AXI CDMA engine, it does transfers between memory-mapped source
-address and a memory-mapped destination address.
-
-Required properties:
-- compatible: Should be "xlnx,axi-vdma-1.00.a" or "xlnx,axi-dma-1.00.a" or
-             "xlnx,axi-cdma-1.00.a""
-- #dma-cells: Should be <1>, see "dmas" property below
-- reg: Should contain VDMA registers location and length.
-- xlnx,addrwidth: Should be the vdma addressing size in bits(ex: 32 bits).
-- dma-ranges: Should be as the following <dma_addr cpu_addr max_len>.
-- dma-channel child node: Should have at least one channel and can have up to
-       two channels per device. This node specifies the properties of each
-       DMA channel (see child node properties below).
-- clocks: Input clock specifier. Refer to common clock bindings.
-- clock-names: List of input clocks
-       For VDMA:
-       Required elements: "s_axi_lite_aclk"
-       Optional elements: "m_axi_mm2s_aclk" "m_axi_s2mm_aclk",
-                          "m_axis_mm2s_aclk", "s_axis_s2mm_aclk"
-       For CDMA:
-       Required elements: "s_axi_lite_aclk", "m_axi_aclk"
-       FOR AXIDMA:
-       Required elements: "s_axi_lite_aclk"
-       Optional elements: "m_axi_mm2s_aclk", "m_axi_s2mm_aclk",
-                          "m_axi_sg_aclk"
-
-Required properties for VDMA:
-- xlnx,num-fstores: Should be the number of framebuffers as configured in h/w.
-
-Optional properties:
-- xlnx,include-sg: Tells configured for Scatter-mode in
-       the hardware.
-Optional properties for VDMA:
-- xlnx,flush-fsync: Tells which channel to Flush on Frame sync.
-       It takes following values:
-       {1}, flush both channels
-       {2}, flush mm2s channel
-       {3}, flush s2mm channel
-
-Required child node properties:
-- compatible: It should be either "xlnx,axi-vdma-mm2s-channel" or
-       "xlnx,axi-vdma-s2mm-channel".
-- interrupts: Should contain per channel VDMA interrupts.
-- xlnx,datawidth: Should contain the stream data width, take values
-       {32,64...1024}.
-
-Optional child node properties:
-- xlnx,include-dre: Tells hardware is configured for Data
-       Realignment Engine.
-Optional child node properties for VDMA:
-- xlnx,genlock-mode: Tells Genlock synchronization is
-       enabled/disabled in hardware.
-
-Example:
-++++++++
-
-axi_vdma_0: axivdma@40030000 {
-       compatible = "xlnx,axi-vdma-1.00.a";
-       #dma_cells = <1>;
-       reg = < 0x40030000 0x10000 >;
-       dma-ranges = <0x00000000 0x00000000 0x40000000>;
-       xlnx,num-fstores = <0x8>;
-       xlnx,flush-fsync = <0x1>;
-       xlnx,addrwidth = <0x20>;
-       clocks = <&clk 0>, <&clk 1>, <&clk 2>, <&clk 3>, <&clk 4>;
-       clock-names = "s_axi_lite_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk",
-                     "m_axis_mm2s_aclk", "s_axis_s2mm_aclk";
-       dma-channel@40030000 {
-               compatible = "xlnx,axi-vdma-mm2s-channel";
-               interrupts = < 0 54 4 >;
-               xlnx,datawidth = <0x40>;
-       } ;
-       dma-channel@40030030 {
-               compatible = "xlnx,axi-vdma-s2mm-channel";
-               interrupts = < 0 53 4 >;
-               xlnx,datawidth = <0x40>;
-       } ;
-} ;
-
-
-* DMA client
-
-Required properties:
-- dmas: a list of <[Video DMA device phandle] [Channel ID]> pairs,
-       where Channel ID is '0' for write/tx and '1' for read/rx
-       channel.
-- dma-names: a list of DMA channel names, one per "dmas" entry
-
-Example:
-++++++++
-
-vdmatest_0: vdmatest@0 {
-       compatible ="xlnx,axi-vdma-test-1.00.a";
-       dmas = <&axi_vdma_0 0
-               &axi_vdma_0 1>;
-       dma-names = "vdma0", "vdma1";
-} ;
diff --git a/Documentation/devicetree/bindings/dma/xilinx/zynqmp_dma.txt b/Documentation/devicetree/bindings/dma/xilinx/zynqmp_dma.txt
new file mode 100644 (file)
index 0000000..a784cdd
--- /dev/null
@@ -0,0 +1,27 @@
+Xilinx ZynqMP DMA engine, it does support memory to memory transfers,
+memory to device and device to memory transfers. It also has flow
+control and rate control support for slave/peripheral dma access.
+
+Required properties:
+- compatible           : Should be "xlnx,zynqmp-dma-1.0"
+- reg                  : Memory map for gdma/adma module access.
+- interrupt-parent     : Interrupt controller the interrupt is routed through
+- interrupts           : Should contain DMA channel interrupt.
+- xlnx,bus-width       : Axi buswidth in bits. Should contain 128 or 64
+- clock-names          : List of input clocks "clk_main", "clk_apb"
+                         (see clock bindings for details)
+
+Optional properties:
+- dma-coherent         : Present if dma operations are coherent.
+
+Example:
+++++++++
+fpd_dma_chan1: dma@fd500000 {
+       compatible = "xlnx,zynqmp-dma-1.0";
+       reg = <0x0 0xFD500000 0x1000>;
+       interrupt-parent = <&gic>;
+       interrupts = <0 117 4>;
+       clock-names = "clk_main", "clk_apb";
+       xlnx,bus-width = <128>;
+       dma-coherent;
+};
diff --git a/Documentation/devicetree/bindings/gpio/gpio_oxnas.txt b/Documentation/devicetree/bindings/gpio/gpio_oxnas.txt
new file mode 100644 (file)
index 0000000..928ed4f
--- /dev/null
@@ -0,0 +1,47 @@
+* Oxford Semiconductor OXNAS SoC GPIO Controller
+
+Please refer to gpio.txt for generic information regarding GPIO bindings.
+
+Required properties:
+ - compatible: "oxsemi,ox810se-gpio"
+ - reg: Base address and length for the device.
+ - interrupts: The port interrupt shared by all pins.
+ - gpio-controller: Marks the port as GPIO controller.
+ - #gpio-cells: Two. The first cell is the pin number and
+   the second cell is used to specify the gpio polarity as defined in
+   defined in <dt-bindings/gpio/gpio.h>:
+      0 = GPIO_ACTIVE_HIGH
+      1 = GPIO_ACTIVE_LOW
+ - interrupt-controller: Marks the device node as an interrupt controller.
+ - #interrupt-cells: Two. The first cell is the GPIO number and second cell
+   is used to specify the trigger type as defined in
+   <dt-bindings/interrupt-controller/irq.h>:
+      IRQ_TYPE_EDGE_RISING
+      IRQ_TYPE_EDGE_FALLING
+      IRQ_TYPE_EDGE_BOTH
+ - gpio-ranges: Interaction with the PINCTRL subsystem, it also specifies the
+   gpio base and count, should be in the format of numeric-gpio-range as
+   specified in the gpio.txt file.
+
+Example:
+
+gpio0: gpio@0 {
+       compatible = "oxsemi,ox810se-gpio";
+       reg = <0x000000 0x100000>;
+       interrupts = <21>;
+       #gpio-cells = <2>;
+       gpio-controller;
+       interrupt-controller;
+       #interrupt-cells = <2>;
+       gpio-ranges = <&pinctrl 0 0 32>;
+};
+
+keys {
+       ...
+
+       button-esc {
+               label = "ESC";
+               linux,code = <1>;
+               gpios = <&gpio0 12 0>;
+       };
+};
index e427792..a73cbeb 100644 (file)
@@ -3,8 +3,22 @@ Broadcom iProc GPIO/PINCONF Controller
 Required properties:
 
 - compatible:
-    Must be "brcm,cygnus-ccm-gpio", "brcm,cygnus-asiu-gpio",
-    "brcm,cygnus-crmu-gpio" or "brcm,iproc-gpio"
+    "brcm,iproc-gpio" for the generic iProc based GPIO controller IP that
+    supports full-featured pinctrl and GPIO functions used in various iProc
+    based SoCs
+
+    May contain an SoC-specific compatibility string to accommodate any
+    SoC-specific features
+
+    "brcm,cygnus-ccm-gpio", "brcm,cygnus-asiu-gpio", or
+    "brcm,cygnus-crmu-gpio" for Cygnus SoCs
+
+    "brcm,iproc-nsp-gpio" for the iProc NSP SoC that has drive strength support
+    disabled
+
+    "brcm,iproc-stingray-gpio" for the iProc Stingray SoC that has the general
+    pinctrl support completely disabled in this IP block. In Stingray, a
+    different IP block is used to handle pinctrl related functions
 
 - reg:
     Define the base and range of the I/O address space that contains SoC
diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,nsp-pinmux.txt b/Documentation/devicetree/bindings/pinctrl/brcm,nsp-pinmux.txt
new file mode 100644 (file)
index 0000000..603564e
--- /dev/null
@@ -0,0 +1,79 @@
+Broadcom NSP (Northstar plus) IOMUX Controller
+
+The NSP IOMUX controller supports group based mux configuration. In
+addition, certain pins can be muxed to GPIO function individually.
+
+Required properties:
+- compatible:
+    Must be "brcm,nsp-pinmux"
+
+- reg:
+    Should contain the register physical address and length for each of
+    GPIO_CONTROL0, GP_AUX_SEL and IPROC_CONFIG IOMUX registers
+
+Properties in subnodes:
+- function:
+    The mux function to select
+
+- groups:
+    The list of groups to select with a given function
+
+For more details, refer to
+Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+
+For example:
+
+       pinmux: pinmux@1803f1c0 {
+               compatible = "brcm,nsp-pinmux";
+               reg = <0x1803f1c0 0x04>,
+                     <0x18030028 0x04>,
+                     <0x1803f408 0x04>;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&pwm &gpio_b &nand_sel>;
+
+               pwm: pwm {
+                       function = "pwm";
+                       groups = "pwm0_grp", "pwm1_grp";
+               };
+
+               gpio_b: gpio_b {
+                       function = "gpio_b";
+                       groups = "gpio_b_0_grp", "gpio_b_1_grp";
+               };
+
+               nand_sel: nand_sel {
+                       function = "nand";
+                       groups = "nand_grp";
+               };
+       };
+
+List of supported functions and groups in Northstar Plus:
+
+"spi": "spi_grp"
+
+"i2c": "i2c_grp"
+
+"mdio": "mdio_grp"
+
+"pwm": "pwm0_grp", "pwm1_grp", "pwm2_grp", "pwm3_grp"
+
+"gpio_b": "gpio_b_0_grp", "gpio_b_1_grp", "gpio_b_2_grp", "gpio_b_3_grp"
+
+"uart1": "uart1_grp"
+
+"uart2": "uart2_grp"
+
+"synce": "synce_grp"
+
+"sata_led_grps": "sata0_led_grp", "sata1_led_grp"
+
+"xtal_out": "xtal_out_grp"
+
+"sdio": "sdio_pwr_grp", "sdio_1p8v_grp"
+
+"switch_led": "switch_p05_led0_grp", "switch_p05_led1_grp"
+
+"nand": "nand_grp"
+
+"emmc": "emmc_grp"
diff --git a/Documentation/devicetree/bindings/pinctrl/oxnas,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/oxnas,pinctrl.txt
new file mode 100644 (file)
index 0000000..d607432
--- /dev/null
@@ -0,0 +1,57 @@
+* Oxford Semiconductor OXNAS SoC Family Pin Controller
+
+Please refer to pinctrl-bindings.txt, ../gpio/gpio.txt, and
+../interrupt-controller/interrupts.txt for generic information regarding
+pin controller, GPIO, and interrupt bindings.
+
+OXNAS 'pin configuration node' is a node of a group of pins which can be
+used for a specific device or function. This node represents configurations of
+pins, optional function, and optional mux related configuration.
+
+Required properties for pin controller node:
+ - compatible: "oxsemi,ox810se-pinctrl"
+ - oxsemi,sys-ctrl: a phandle to the system controller syscon node
+
+Required properties for pin configuration sub-nodes:
+ - pins: List of pins to which the configuration applies.
+
+Optional properties for pin configuration sub-nodes:
+----------------------------------------------------
+ - function: Mux function for the specified pins.
+ - bias-pull-up: Enable weak pull-up.
+
+Example:
+
+pinctrl: pinctrl {
+       compatible = "oxsemi,ox810se-pinctrl";
+
+       /* Regmap for sys registers */
+       oxsemi,sys-ctrl = <&sys>;
+
+       pinctrl_uart2: pinctrl_uart2 {
+               uart2a {
+                       pins = "gpio31";
+                       function = "fct3";
+               };
+               uart2b {
+                       pins = "gpio32";
+                       function = "fct3";
+               };
+       };
+};
+
+uart2: serial@900000 {
+       compatible = "ns16550a";
+       reg = <0x900000 0x100000>;
+       clocks = <&sysclk>;
+       interrupts = <29>;
+       reg-shift = <0>;
+       fifo-size = <16>;
+       reg-io-width = <1>;
+       current-speed = <115200>;
+       no-loopback-test;
+       status = "disabled";
+       resets = <&reset 22>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-max77620.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-max77620.txt
new file mode 100644 (file)
index 0000000..ad4fce3
--- /dev/null
@@ -0,0 +1,127 @@
+Pincontrol driver for MAX77620 Power management IC from Maxim Semiconductor.
+
+Device has 8 GPIO pins which can be configured as GPIO as well as the
+special IO functions.
+
+Please refer file <devicetree/bindings/pinctrl/pinctrl-bindings.txt>
+for details of the common pinctrl bindings used by client devices,
+including the meaning of the phrase "pin configuration node".
+
+Optional Pinmux properties:
+--------------------------
+Following properties are required if default setting of pins are required
+at boot.
+- pinctrl-names: A pinctrl state named per <pinctrl-binding.txt>.
+- pinctrl[0...n]: Properties to contain the phandle for pinctrl states per
+               <pinctrl-binding.txt>.
+
+The pin configurations are defined as child of the pinctrl states node. Each
+sub-node have following properties:
+
+Required properties:
+------------------
+- pins: List of pins. Valid values of pins properties are:
+                     gpio0, gpio1, gpio2, gpio3, gpio4, gpio5, gpio6, gpio7.
+
+Optional properties:
+-------------------
+Following are optional properties defined as pinmux DT binding document
+<pinctrl-bindings.txt>. Absence of properties will leave the configuration
+on default.
+       function,
+       drive-push-pull,
+       drive-open-drain,
+       bias-pull-up,
+       bias-pull-down.
+
+Valid values for function properties are:
+       gpio, lpm-control-in, fps-out, 32k-out, sd0-dvs-in, sd1-dvs-in,
+       reference-out
+
+Theres is also customised properties for the GPIO1, GPIO2 and GPIO3. These
+customised properties are required to configure FPS configuration parameters
+of these GPIOs. Please refer <devicetree/bindings/mfd/max77620.txt> for more
+detail of Flexible Power Sequence (FPS).
+
+- maxim,active-fps-source:             FPS source for the GPIOs to get
+                                       enabled/disabled when system is in
+                                       active state.  Valid values are:
+                                       - MAX77620_FPS_SRC_0,
+                                               FPS source is FPS0.
+                                       - MAX77620_FPS_SRC_1,
+                                               FPS source is FPS1
+                                       - MAX77620_FPS_SRC_2 and
+                                               FPS source is FPS2
+                                       - MAX77620_FPS_SRC_NONE.
+                                               GPIO is not controlled
+                                               by FPS events and it gets
+                                               enabled/disabled by register
+                                               access.
+                                       Absence of this property will leave
+                                       the FPS configuration register for that
+                                       GPIO to default configuration.
+
+- maxim,active-fps-power-up-slot:      Sequencing event slot number on which
+                                       the GPIO get enabled when
+                                       master FPS input event set to HIGH.
+                                       Valid values are 0 to 7.
+                                       This is applicable if FPS source is
+                                       selected as FPS0, FPS1 or FPS2.
+
+- maxim,active-fps-power-down-slot:    Sequencing event slot number on which
+                                       the GPIO get disabled when master
+                                       FPS input event set to LOW.
+                                       Valid values are 0 to 7.
+                                       This is applicable if FPS source is
+                                       selected as FPS0, FPS1 or FPS2.
+
+- maxim,suspend-fps-source:            This is same as property
+                                       "maxim,active-fps-source" but value
+                                       get configured when system enters in
+                                       to suspend state.
+
+- maxim,suspend-fps-power-up-slot:     This is same as property
+                                       "maxim,active-fps-power-up-slot" but
+                                       this value get configured into FPS
+                                       configuration register when system
+                                       enters into suspend.
+                                       This is applicable if suspend state
+                                       FPS source is selected as FPS0, FPS1 or
+
+- maxim,suspend-fps-power-down-slot:   This is same as property
+                                       "maxim,active-fps-power-down-slot" but
+                                       this value get configured into FPS
+                                       configuration register when system
+                                       enters into suspend.
+                                       This is applicable if suspend state
+                                       FPS source is selected as FPS0, FPS1 or
+                                       FPS2.
+
+Example:
+--------
+#include <dt-bindings/mfd/max77620.h>
+...
+max77620@3c {
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&spmic_default>;
+
+       spmic_default: pinmux@0 {
+               pin_gpio0 {
+                       pins = "gpio0";
+                       function = "gpio";
+               };
+
+               pin_gpio1 {
+                       pins = "gpio1";
+                       function = "fps-out";
+                       maxim,active-fps-source = <MAX77620_FPS_SRC_0>;
+               };
+
+               pin_gpio2 {
+                       pins = "gpio2";
+                       function = "fps-out";
+                       maxim,active-fps-source = <MAX77620_FPS_SRC_1>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,mdm9615-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,mdm9615-pinctrl.txt
new file mode 100644 (file)
index 0000000..1b52f01
--- /dev/null
@@ -0,0 +1,152 @@
+Qualcomm MDM9615 TLMM block
+
+This binding describes the Top Level Mode Multiplexer block found in the
+MDM9615 platform.
+
+- compatible:
+       Usage: required
+       Value type: <string>
+       Definition: must be "qcom,mdm9615-pinctrl"
+
+- reg:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: the base address and size of the TLMM register space.
+
+- interrupts:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: should specify the TLMM summary IRQ.
+
+- interrupt-controller:
+       Usage: required
+       Value type: <none>
+       Definition: identifies this node as an interrupt controller
+
+- #interrupt-cells:
+       Usage: required
+       Value type: <u32>
+       Definition: must be 2. Specifying the pin number and flags, as defined
+                   in <dt-bindings/interrupt-controller/irq.h>
+
+- gpio-controller:
+       Usage: required
+       Value type: <none>
+       Definition: identifies this node as a gpio controller
+
+- #gpio-cells:
+       Usage: required
+       Value type: <u32>
+       Definition: must be 2. Specifying the pin number and flags, as defined
+                   in <dt-bindings/gpio/gpio.h>
+
+Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for
+a general description of GPIO and interrupt bindings.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+The pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin, a group, or a list of pins or groups. This configuration can include the
+mux function to select on those pin(s)/group(s), and various pin configuration
+parameters, such as pull-up, drive strength, etc.
+
+
+PIN CONFIGURATION NODES:
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Each subnode only affects those parameters that are explicitly listed. In
+other words, a subnode that lists a mux function but no pin configuration
+parameters implies no information about any pin configuration parameters.
+Similarly, a pin subnode that describes a pullup parameter implies no
+information about e.g. the mux function.
+
+
+The following generic properties as defined in pinctrl-bindings.txt are valid
+to specify in a pin configuration subnode:
+
+- pins:
+       Usage: required
+       Value type: <string-array>
+       Definition: List of gpio pins affected by the properties specified in
+                   this subnode.  Valid pins are:
+                   gpio0-gpio87
+
+- function:
+       Usage: required
+       Value type: <string>
+       Definition: Specify the alternative function to be configured for the
+                   specified pins.
+                   Valid values are:
+                   gpio, gsbi2_i2c, gsbi3, gsbi4, gsbi5_i2c, gsbi5_uart,
+                   sdc2, ebi2_lcdc, ps_hold, prim_audio, sec_audio,
+                   cdc_mclk
+
+- bias-disable:
+       Usage: optional
+       Value type: <none>
+       Definition: The specified pins should be configued as no pull.
+
+- bias-pull-down:
+       Usage: optional
+       Value type: <none>
+       Definition: The specified pins should be configued as pull down.
+
+- bias-pull-up:
+       Usage: optional
+       Value type: <none>
+       Definition: The specified pins should be configued as pull up.
+
+- output-high:
+       Usage: optional
+       Value type: <none>
+       Definition: The specified pins are configured in output mode, driven
+                   high.
+
+- output-low:
+       Usage: optional
+       Value type: <none>
+       Definition: The specified pins are configured in output mode, driven
+                   low.
+
+- drive-strength:
+       Usage: optional
+       Value type: <u32>
+       Definition: Selects the drive strength for the specified pins, in mA.
+                   Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16
+
+Example:
+
+       msmgpio: pinctrl@800000 {
+               compatible = "qcom,mdm9615-pinctrl";
+               reg = <0x800000 0x4000>;
+
+               gpio-controller;
+               #gpio-cells = <2>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
+               interrupts = <0 16 0x4>;
+
+               gsbi8_uart: gsbi8-uart {
+                       mux {
+                               pins = "gpio34", "gpio35";
+                               function = "gsbi8";
+                       };
+
+                       tx {
+                               pins = "gpio34";
+                               drive-strength = <4>;
+                               bias-disable;
+                       };
+
+                       rx {
+                               pins = "gpio35";
+                               drive-strength = <2>;
+                               bias-pull-up;
+                       };
+               };
+       };
index 77aa117..df9a838 100644 (file)
@@ -52,7 +52,7 @@ Valid values for function are:
   gsbi2_spi_cs3_n, gsbi3, gsbi3_spi_cs1_n, gsbi3_spi_cs2_n, gsbi3_spi_cs3_n,
   gsbi4, gsbi5, gsbi6, gsbi7, gsbi8, gsbi9, gsbi10, gsbi11, gsbi12, hdmi, i2s,
   lcdc, mdp_vsync, mi2s, pcm, ps_hold, sdc1, sdc2, sdc5, tsif1, tsif2, usb_fs1,
-  usb_fs1_oe_n, usb_fs2, usb_fs2_oe_n, vfe, vsens_alarm,
+  usb_fs1_oe_n, usb_fs2, usb_fs2_oe_n, vfe, vsens_alarm, ebi2, ebi2cs
 
 Example:
 
index e4d6a9d..453bd7c 100644 (file)
@@ -49,6 +49,9 @@ Valid values for pins are:
   sdc1_clk, sdc1_cmd, sdc1_data, sdc2_clk, sdc2_cmd, sdc2_data
     Supports bias and drive-strength
 
+  hsic_data, hsic_strobe
+    Supports only mux
+
 Valid values for function are:
   cci_i2c0, cci_i2c1, uim1, uim2, uim_batt_alarm,
   blsp_uim1, blsp_uart1, blsp_i2c1, blsp_spi1,
@@ -70,7 +73,7 @@ Valid values for function are:
   cam_mckl0, cam_mclk1, cam_mclk2, cam_mclk3, mdp_vsync, hdmi_cec, hdmi_ddc,
   hdmi_hpd, edp_hpd, gp_pdm0, gp_pdm1, gp_pdm2, gp_pdm3, gp0_clk, gp1_clk,
   gp_mn, tsif1, tsif2, hsic, grfc, audio_ref_clk, qua_mi2s, pri_mi2s, spkr_mi2s,
-  ter_mi2s, sec_mi2s, bt, fm, wlan, slimbus, gpio
+  ter_mi2s, sec_mi2s, bt, fm, wlan, slimbus, hsic_ctl, gpio
 
   (Note that this is not yet the complete list of functions)
 
index d74e631..b484ba1 100644 (file)
@@ -9,6 +9,7 @@ of PMIC's from Qualcomm.
        Definition: Should contain one of:
                    "qcom,pm8018-mpp",
                    "qcom,pm8038-mpp",
+                   "qcom,pm8058-mpp",
                    "qcom,pm8821-mpp",
                    "qcom,pm8841-mpp",
                    "qcom,pm8916-mpp",
index 74e6ec0..e4cf022 100644 (file)
@@ -72,7 +72,7 @@ Pin Configuration Node Properties:
 
 The pin configuration parameters use the generic pinconf bindings defined in
 pinctrl-bindings.txt in this directory. The supported parameters are
-bias-disable, bias-pull-up, bias-pull-down, drive strength and power-source. For
+bias-disable, bias-pull-up, bias-pull-down, drive-strength and power-source. For
 pins that have a configurable I/O voltage, the power-source value should be the
 nominal I/O voltage in millivolts.
 
index 7b4800c..587bffb 100644 (file)
@@ -9,6 +9,7 @@ Pin controller node:
 Required properies:
  - compatible: value should be one of the following:
    (a) "st,stm32f429-pinctrl"
+   (b) "st,stm32f746-pinctrl"
  - #address-cells: The value of this property must be 1
  - #size-cells : The value of this property must be 1
  - ranges      : defines mapping between pin controller node (parent) to
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt b/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt
new file mode 100644 (file)
index 0000000..57cb49e
--- /dev/null
@@ -0,0 +1,137 @@
+Qualcomm Hexagon Peripheral Image Loader
+
+This document defines the binding for a component that loads and boots firmware
+on the Qualcomm Hexagon core.
+
+- compatible:
+       Usage: required
+       Value type: <string>
+       Definition: must be one of:
+                   "qcom,q6v5-pil"
+
+- reg:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: must specify the base address and size of the qdsp6 and
+                   rmb register blocks
+
+- reg-names:
+       Usage: required
+       Value type: <stringlist>
+       Definition: must be "q6dsp" and "rmb"
+
+- interrupts-extended:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: must list the watchdog, fatal IRQs ready, handover and
+                   stop-ack IRQs
+
+- interrupt-names:
+       Usage: required
+       Value type: <stringlist>
+       Definition: must be "wdog", "fatal", "ready", "handover", "stop-ack"
+
+- clocks:
+       Usage: required
+       Value type: <phandle>
+       Definition: reference to the iface, bus and mem clocks to be held on
+                   behalf of the booting of the Hexagon core
+
+- clock-names:
+       Usage: required
+       Value type: <stringlist>
+       Definition: must be "iface", "bus", "mem"
+
+- resets:
+       Usage: required
+       Value type: <phandle>
+       Definition: reference to the reset-controller for the modem sub-system
+
+- reset-names:
+       Usage: required
+       Value type: <stringlist>
+       Definition: must be "mss_restart"
+
+- cx-supply:
+- mss-supply:
+- mx-supply:
+- pll-supply:
+       Usage: required
+       Value type: <phandle>
+       Definition: reference to the regulators to be held on behalf of the
+                   booting of the Hexagon core
+
+- qcom,smem-states:
+       Usage: required
+       Value type: <phandle>
+       Definition: reference to the smem state for requesting the Hexagon to
+                   shut down
+
+- qcom,smem-state-names:
+       Usage: required
+       Value type: <stringlist>
+       Definition: must be "stop"
+
+- qcom,halt-regs:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: a phandle reference to a syscon representing TCSR followed
+                   by the three offsets within syscon for q6, modem and nc
+                   halt registers.
+
+= SUBNODES:
+The Hexagon node must contain two subnodes, named "mba" and "mpss" representing
+the memory regions used by the Hexagon firmware. Each sub-node must contain:
+
+- memory-region:
+       Usage: required
+       Value type: <phandle>
+       Definition: reference to the reserved-memory for the region
+
+= EXAMPLE
+The following example describes the resources needed to boot control the
+Hexagon, as it is found on MSM8974 boards.
+
+       modem-rproc@fc880000 {
+               compatible = "qcom,q6v5-pil";
+               reg = <0xfc880000 0x100>,
+                     <0xfc820000 0x020>;
+               reg-names = "qdsp6", "rmb";
+
+               interrupts-extended = <&intc 0 24 1>,
+                                     <&modem_smp2p_in 0 0>,
+                                     <&modem_smp2p_in 1 0>,
+                                     <&modem_smp2p_in 2 0>,
+                                     <&modem_smp2p_in 3 0>;
+               interrupt-names = "wdog",
+                                 "fatal",
+                                 "ready",
+                                 "handover",
+                                 "stop-ack";
+
+               clocks = <&gcc GCC_MSS_Q6_BIMC_AXI_CLK>,
+                        <&gcc GCC_MSS_CFG_AHB_CLK>,
+                        <&gcc GCC_BOOT_ROM_AHB_CLK>;
+               clock-names = "iface", "bus", "mem";
+
+               qcom,halt-regs = <&tcsr_mutex_block 0x1180 0x1200 0x1280>;
+
+               resets = <&gcc GCC_MSS_RESTART>;
+               reset-names = "mss_restart";
+
+               cx-supply = <&pm8841_s2>;
+               mss-supply = <&pm8841_s3>;
+               mx-supply = <&pm8841_s1>;
+               pll-supply = <&pm8941_l12>;
+
+               qcom,smem-states = <&modem_smp2p_out 0>;
+               qcom,smem-state-names = "stop";
+
+               mba {
+                       memory-region = <&mba_region>;
+               };
+
+               mpss {
+                       memory-region = <&mpss_region>;
+               };
+       };
index 5a7386e..1b3c39a 100644 (file)
@@ -15,11 +15,14 @@ prototypes:
        int (*d_compare)(const struct dentry *, const struct dentry *,
                        unsigned int, const char *, const struct qstr *);
        int (*d_delete)(struct dentry *);
+       int (*d_init)(struct dentry *);
        void (*d_release)(struct dentry *);
        void (*d_iput)(struct dentry *, struct inode *);
        char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
        struct vfsmount *(*d_automount)(struct path *path);
        int (*d_manage)(struct dentry *, bool);
+       struct dentry *(*d_real)(struct dentry *, const struct inode *,
+                                unsigned int);
 
 locking rules:
                rename_lock     ->d_lock        may block       rcu-walk
@@ -28,12 +31,14 @@ d_weak_revalidate:no                no              yes             no
 d_hash         no              no              no              maybe
 d_compare:     yes             no              no              maybe
 d_delete:      no              yes             no              no
+d_init:        no              no              yes             no
 d_release:     no              no              yes             no
 d_prune:        no              yes             no              no
 d_iput:                no              no              yes             no
 d_dname:       no              no              no              no
 d_automount:   no              no              yes             no
 d_manage:      no              no              yes (ref-walk)  maybe
+d_real         no              no              yes             no
 
 --------------------------- inode_operations --------------------------- 
 prototypes:
@@ -66,7 +71,6 @@ prototypes:
                                struct file *, unsigned open_flag,
                                umode_t create_mode, int *opened);
        int (*tmpfile) (struct inode *, struct dentry *, umode_t);
-       int (*dentry_open)(struct dentry *, struct file *, const struct cred *);
 
 locking rules:
        all may block
@@ -95,7 +99,6 @@ fiemap:               no
 update_time:   no
 atomic_open:   yes
 tmpfile:       no
-dentry_open:   no
 
        Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
 victim.
@@ -179,7 +182,6 @@ unlocks and drops the reference.
 prototypes:
        int (*writepage)(struct page *page, struct writeback_control *wbc);
        int (*readpage)(struct file *, struct page *);
-       int (*sync_page)(struct page *);
        int (*writepages)(struct address_space *, struct writeback_control *);
        int (*set_page_dirty)(struct page *page);
        int (*readpages)(struct file *filp, struct address_space *mapping,
@@ -210,7 +212,6 @@ locking rules:
                        PageLocked(page)        i_mutex
 writepage:             yes, unlocks (see below)
 readpage:              yes, unlocks
-sync_page:             maybe
 writepages:
 set_page_dirty         no
 readpages:
@@ -230,8 +231,8 @@ error_remove_page:  yes
 swap_activate:         no
 swap_deactivate:       no
 
-       ->write_begin(), ->write_end(), ->sync_page() and ->readpage()
-may be called from the request handler (/dev/loop).
+       ->write_begin(), ->write_end() and ->readpage() may be called from
+the request handler (/dev/loop).
 
        ->readpage() unlocks the page, either synchronously or via I/O
 completion.
@@ -287,11 +288,6 @@ will leave the page itself marked clean but it will be tagged as dirty in the
 radix tree.  This incoherency can lead to all sorts of hard-to-debug problems
 in the filesystem like having dirty inodes at umount and losing written data.
 
-       ->sync_page() locking rules are not well-defined - usually it is called
-with lock on page, but that is not guaranteed. Considering the currently
-existing instances of this method ->sync_page() itself doesn't look
-well-defined...
-
        ->writepages() is used for periodic writeback and for syscall-initiated
 sync operations.  The address_space should start I/O against at least
 *nr_to_write pages.  *nr_to_write must be decremented for each page which is
@@ -399,7 +395,7 @@ prototypes:
        int (*release) (struct gendisk *, fmode_t);
        int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
        int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
-       int (*direct_access) (struct block_device *, sector_t, void __pmem **,
+       int (*direct_access) (struct block_device *, sector_t, void **,
                                unsigned long *);
        int (*media_changed) (struct gendisk *);
        void (*unlock_native_capacity) (struct gendisk *);
index 900360c..8a19685 100644 (file)
@@ -364,7 +364,6 @@ struct inode_operations {
        int (*atomic_open)(struct inode *, struct dentry *, struct file *,
                        unsigned open_flag, umode_t create_mode, int *opened);
        int (*tmpfile) (struct inode *, struct dentry *, umode_t);
-       int (*dentry_open)(struct dentry *, struct file *, const struct cred *);
 };
 
 Again, all methods are called without any locks being held, unless
@@ -534,9 +533,7 @@ __sync_single_inode) to check if ->writepages has been successful in
 writing out the whole address_space.
 
 The Writeback tag is used by filemap*wait* and sync_page* functions,
-via filemap_fdatawait_range, to wait for all writeback to
-complete.  While waiting ->sync_page (if defined) will be called on
-each page that is found to require writeback.
+via filemap_fdatawait_range, to wait for all writeback to complete.
 
 An address_space handler may attach extra information to a page,
 typically using the 'private' field in the 'struct page'.  If such
@@ -554,8 +551,8 @@ address_space has finer control of write sizes.
 
 The read process essentially only requires 'readpage'.  The write
 process is more complicated and uses write_begin/write_end or
-set_page_dirty to write data into the address_space, and writepage,
-sync_page, and writepages to writeback data to storage.
+set_page_dirty to write data into the address_space, and writepage
+and writepages to writeback data to storage.
 
 Adding and removing pages to/from an address_space is protected by the
 inode's i_mutex.
@@ -701,13 +698,6 @@ struct address_space_operations {
        but instead uses bmap to find out where the blocks in the file
        are and uses those addresses directly.
 
-  dentry_open: *WARNING: probably going away soon, do not use!* This is an
-       alternative to f_op->open(), the difference is that this method may open
-       a file not necessarily originating from the same filesystem as the one
-       i_op->open() was called on.  It may be useful for stacking filesystems
-       which want to allow native I/O directly on underlying files.
-
-
   invalidatepage: If a page has PagePrivate set, then invalidatepage
         will be called when part or all of the page is to be removed
        from the address space.  This generally corresponds to either a
@@ -944,11 +934,14 @@ struct dentry_operations {
        int (*d_compare)(const struct dentry *, const struct dentry *,
                        unsigned int, const char *, const struct qstr *);
        int (*d_delete)(const struct dentry *);
+       int (*d_init)(struct dentry *);
        void (*d_release)(struct dentry *);
        void (*d_iput)(struct dentry *, struct inode *);
        char *(*d_dname)(struct dentry *, char *, int);
        struct vfsmount *(*d_automount)(struct path *);
        int (*d_manage)(struct dentry *, bool);
+       struct dentry *(*d_real)(struct dentry *, const struct inode *,
+                                unsigned int);
 };
 
   d_revalidate: called when the VFS needs to revalidate a dentry. This
@@ -1014,6 +1007,8 @@ struct dentry_operations {
        always cache a reachable dentry. d_delete must be constant and
        idempotent.
 
+  d_init: called when a dentry is allocated
+
   d_release: called when a dentry is really deallocated
 
   d_iput: called when a dentry loses its inode (just prior to its
@@ -1033,6 +1028,14 @@ struct dentry_operations {
        at the end of the buffer, and returns a pointer to the first char.
        dynamic_dname() helper function is provided to take care of this.
 
+       Example :
+
+       static char *pipefs_dname(struct dentry *dent, char *buffer, int buflen)
+       {
+               return dynamic_dname(dentry, buffer, buflen, "pipe:[%lu]",
+                               dentry->d_inode->i_ino);
+       }
+
   d_automount: called when an automount dentry is to be traversed (optional).
        This should create a new VFS mount record and return the record to the
        caller.  The caller is supplied with a path parameter giving the
@@ -1071,13 +1074,23 @@ struct dentry_operations {
        This function is only used if DCACHE_MANAGE_TRANSIT is set on the
        dentry being transited from.
 
-Example :
+  d_real: overlay/union type filesystems implement this method to return one of
+       the underlying dentries hidden by the overlay.  It is used in three
+       different modes:
 
-static char *pipefs_dname(struct dentry *dent, char *buffer, int buflen)
-{
-       return dynamic_dname(dentry, buffer, buflen, "pipe:[%lu]",
-                               dentry->d_inode->i_ino);
-}
+       Called from open it may need to copy-up the file depending on the
+       supplied open flags.  This mode is selected with a non-zero flags
+       argument.  In this mode the d_real method can return an error.
+
+       Called from file_dentry() it returns the real dentry matching the inode
+       argument.  The real dentry may be from a lower layer already copied up,
+       but still referenced from the file.  This mode is selected with a
+       non-NULL inode argument.  This will always succeed.
+
+       With NULL inode and zero flags the topmost real underlying dentry is
+       returned.  This will always succeed.
+
+       This method is never called with both non-NULL inode and non-zero flags.
 
 Each dentry has a pointer to its parent dentry, as well as a hash list
 of child dentries. Child dentries are basically like files in a
diff --git a/Documentation/hid/hid-alps.txt b/Documentation/hid/hid-alps.txt
new file mode 100644 (file)
index 0000000..6b02a24
--- /dev/null
@@ -0,0 +1,139 @@
+ALPS HID Touchpad Protocol
+----------------------
+
+Introduction
+------------
+Currently ALPS HID driver supports U1 Touchpad device.
+
+U1 devuce basic information.
+Vender ID      0x044E
+Product ID     0x120B
+Version ID     0x0121
+
+
+HID Descriptor
+------------
+Byte   Field                   Value   Notes
+0      wHIDDescLength          001E    Length of HID Descriptor : 30 bytes
+2      bcdVersion              0100    Compliant with Version 1.00
+4      wReportDescLength       00B2    Report Descriptor is 178 Bytes (0x00B2)
+6      wReportDescRegister     0002    Identifier to read Report Descriptor
+8      wInputRegister          0003    Identifier to read Input Report
+10     wMaxInputLength         0053    Input Report is 80 Bytes + 2
+12     wOutputRegister         0000    Identifier to read Output Report
+14     wMaxOutputLength        0000    No Output Reports
+16     wCommandRegister        0005    Identifier for Command Register
+18     wDataRegister           0006    Identifier for Data Register
+20     wVendorID               044E    Vendor ID 0x044E
+22     wProductID              120B    Product ID 0x120B
+24     wVersionID              0121    Version 01.21
+26     RESERVED                0000    RESERVED
+
+
+Report ID
+------------
+ReportID-1     (Input Reports) (HIDUsage-Mouse) for TP&SP
+ReportID-2     (Input Reports) (HIDUsage-keyboard) for TP
+ReportID-3     (Input Reports) (Vendor Usage: Max 10 finger data) for TP
+ReportID-4     (Input Reports) (Vendor Usage: ON bit data) for GP
+ReportID-5     (Feature Reports)       Feature Reports
+ReportID-6     (Input Reports) (Vendor Usage: StickPointer data) for SP
+ReportID-7     (Feature Reports)       Flash update (Bootloader)
+
+
+Data pattern
+------------
+Case1  ReportID_1      TP/SP   Relative/Relative
+Case2  ReportID_3      TP      Absolute
+       ReportID_6      SP      Absolute
+
+
+Command Read/Write
+------------------
+To read/write to RAM, need to send a commands to the device.
+The command format is as below.
+
+DataByte(SET_REPORT)
+Byte1  Command Byte
+Byte2  Address - Byte 0 (LSB)
+Byte3  Address - Byte 1
+Byte4  Address - Byte 2
+Byte5  Address - Byte 3 (MSB)
+Byte6  Value Byte
+Byte7  Checksum
+
+Command Byte is read=0xD1/write=0xD2 .
+Address is read/write RAM address.
+Value Byte is writing data when you send the write commands.
+When you read RAM, there is no meaning.
+
+DataByte(GET_REPORT)
+Byte1  Response Byte
+Byte2  Address - Byte 0 (LSB)
+Byte3  Address - Byte 1
+Byte4  Address - Byte 2
+Byte5  Address - Byte 3 (MSB)
+Byte6  Value Byte
+Byte7  Checksum
+
+Read value is stored in Value Byte.
+
+
+Packet Format
+Touchpad data byte
+------------------
+       b7      b6      b5      b4      b3      b2      b1      b0
+1      0       0       SW6     SW5     SW4     SW3     SW2     SW1
+2      0       0       0       Fcv     Fn3     Fn2     Fn1     Fn0
+3      Xa0_7   Xa0_6   Xa0_5   Xa0_4   Xa0_3   Xa0_2   Xa0_1   Xa0_0
+4      Xa0_15  Xa0_14  Xa0_13  Xa0_12  Xa0_11  Xa0_10  Xa0_9   Xa0_8
+5      Ya0_7   Ya0_6   Ya0_5   Ya0_4   Ya0_3   Ya0_2   Ya0_1   Ya0_0
+6      Ya0_15  Ya0_14  Ya0_13  Ya0_12  Ya0_11  Ya0_10  Ya0_9   Ya0_8
+7      LFB0    Zs0_6   Zs0_5   Zs0_4   Zs0_3   Zs0_2   Zs0_1   Zs0_0
+
+8      Xa1_7   Xa1_6   Xa1_5   Xa1_4   Xa1_3   Xa1_2   Xa1_1   Xa1_0
+9      Xa1_15  Xa1_14  Xa1_13  Xa1_12  Xa1_11  Xa1_10  Xa1_9   Xa1_8
+10     Ya1_7   Ya1_6   Ya1_5   Ya1_4   Ya1_3   Ya1_2   Ya1_1   Ya1_0
+11     Ya1_15  Ya1_14  Ya1_13  Ya1_12  Ya1_11  Ya1_10  Ya1_9   Ya1_8
+12     LFB1    Zs1_6   Zs1_5   Zs1_4   Zs1_3   Zs1_2   Zs1_1   Zs1_0
+
+13     Xa2_7   Xa2_6   Xa2_5   Xa2_4   Xa2_3   Xa2_2   Xa2_1   Xa2_0
+14     Xa2_15  Xa2_14  Xa2_13  Xa2_12  Xa2_11  Xa2_10  Xa2_9   Xa2_8
+15     Ya2_7   Ya2_6   Ya2_5   Ya2_4   Ya2_3   Ya2_2   Ya2_1   Ya2_0
+16     Ya2_15  Ya2_14  Ya2_13  Ya2_12  Ya2_11  Ya2_10  Ya2_9   Ya2_8
+17     LFB2    Zs2_6   Zs2_5   Zs2_4   Zs2_3   Zs2_2   Zs2_1   Zs2_0
+
+18     Xa3_7   Xa3_6   Xa3_5   Xa3_4   Xa3_3   Xa3_2   Xa3_1   Xa3_0
+19     Xa3_15  Xa3_14  Xa3_13  Xa3_12  Xa3_11  Xa3_10  Xa3_9   Xa3_8
+20     Ya3_7   Ya3_6   Ya3_5   Ya3_4   Ya3_3   Ya3_2   Ya3_1   Ya3_0
+21     Ya3_15  Ya3_14  Ya3_13  Ya3_12  Ya3_11  Ya3_10  Ya3_9   Ya3_8
+22     LFB3    Zs3_6   Zs3_5   Zs3_4   Zs3_3   Zs3_2   Zs3_1   Zs3_0
+
+23     Xa4_7   Xa4_6   Xa4_5   Xa4_4   Xa4_3   Xa4_2   Xa4_1   Xa4_0
+24     Xa4_15  Xa4_14  Xa4_13  Xa4_12  Xa4_11  Xa4_10  Xa4_9   Xa4_8
+25     Ya4_7   Ya4_6   Ya4_5   Ya4_4   Ya4_3   Ya4_2   Ya4_1   Ya4_0
+26     Ya4_15  Ya4_14  Ya4_13  Ya4_12  Ya4_11  Ya4_10  Ya4_9   Ya4_8
+27     LFB4    Zs4_6   Zs4_5   Zs4_4   Zs4_3   Zs4_2   Zs4_1   Zs4_0
+
+
+SW1-SW6:       SW ON/OFF status
+Xan_15-0(16bit):X Absolute data of the "n"th finger
+Yan_15-0(16bit):Y Absolute data of the "n"th finger
+Zsn_6-0(7bit): Operation area of the "n"th finger
+
+
+StickPointer data byte
+------------------
+       b7      b6      b5      b4      b3      b2      b1      b0
+Byte1  1       1       1       0       1       SW3     SW2     SW1
+Byte2  X7      X6      X5      X4      X3      X2      X1      X0
+Byte3  X15     X14     X13     X12     X11     X10     X9      X8
+Byte4  Y7      Y6      Y5      Y4      Y3      Y2      Y1      Y0
+Byte5  Y15     Y14     Y13     Y12     Y11     Y10     Y9      Y8
+Byte6  Z7      Z6      Z5      Z4      Z3      Z2      Z1      Z0
+Byte7  T&P     Z14     Z13     Z12     Z11     Z10     Z9      Z8
+
+SW1-SW3:       SW ON/OFF status
+Xn_15-0(16bit):X Absolute data
+Yn_15-0(16bit):Y Absolute data
+Zn_14-0(15bit):Z
index b91443f..e293fb6 100644 (file)
@@ -256,28 +256,18 @@ If any of these error conditions are encountered, the arena is put into a read
 only state using a flag in the info block.
 
 
-5. In-kernel usage
-==================
+5. Usage
+========
 
-Any block driver that supports byte granularity IO to the storage may register
-with the BTT. It will have to provide the rw_bytes interface in its
-block_device_operations struct:
+The BTT can be set up on any disk (namespace) exposed by the libnvdimm subsystem
+(pmem, or blk mode). The easiest way to set up such a namespace is using the
+'ndctl' utility [1]:
 
-       int (*rw_bytes)(struct gendisk *, void *, size_t, off_t, int rw);
+For example, the ndctl command line to setup a btt with a 4k sector size is:
 
-It may register with the BTT after it adds its own gendisk, using btt_init:
+    ndctl create-namespace -f -e namespace0.0 -m sector -l 4k
 
-       struct btt *btt_init(struct gendisk *disk, unsigned long long rawsize,
-                       u32 lbasize, u8 uuid[], int maxlane);
+See ndctl create-namespace --help for more options.
 
-note that maxlane is the maximum amount of concurrency the driver wishes to
-allow the BTT to use.
-
-The BTT 'disk' appears as a stacked block device that grabs the underlying block
-device in the O_EXCL mode.
-
-When the driver wishes to remove the backing disk, it should similarly call
-btt_fini using the same struct btt* handle that was provided to it by btt_init.
-
-       void btt_fini(struct btt *btt);
+[1]: https://github.com/pmem/ndctl
 
index 4976389..0d3b9ce 100644 (file)
@@ -286,13 +286,13 @@ see the section named "pin control requests from drivers" and
 "drivers needing both pin control and GPIOs" below for details. But in some
 situations a cross-subsystem mapping between pins and GPIOs is needed.
 
-Since the pin controller subsystem have its pinspace local to the pin
-controller we need a mapping so that the pin control subsystem can figure out
-which pin controller handles control of a certain GPIO pin. Since a single
-pin controller may be muxing several GPIO ranges (typically SoCs that have
-one set of pins, but internally several GPIO silicon blocks, each modelled as
-a struct gpio_chip) any number of GPIO ranges can be added to a pin controller
-instance like this:
+Since the pin controller subsystem has its pinspace local to the pin controller
+we need a mapping so that the pin control subsystem can figure out which pin
+controller handles control of a certain GPIO pin. Since a single pin controller
+may be muxing several GPIO ranges (typically SoCs that have one set of pins,
+but internally several GPIO silicon blocks, each modelled as a struct
+gpio_chip) any number of GPIO ranges can be added to a pin controller instance
+like this:
 
 struct gpio_chip chip_a;
 struct gpio_chip chip_b;
@@ -493,12 +493,12 @@ Definitions:
 - The combination of a FUNCTION and a PIN GROUP determine a certain function
   for a certain set of pins. The knowledge of the functions and pin groups
   and their machine-specific particulars are kept inside the pinmux driver,
-  from the outside only the enumerators are known, and the driver core can:
+  from the outside only the enumerators are known, and the driver core can
+  request:
 
-  - Request the name of a function with a certain selector (>= 0)
+  - The name of a function with a certain selector (>= 0)
   - A list of groups associated with a certain function
-  - Request that a certain group in that list to be activated for a certain
-    function
+  - That a certain group in that list to be activated for a certain function
 
   As already described above, pin groups are in turn self-descriptive, so
   the core will retrieve the actual pin range in a certain group from the
@@ -831,7 +831,7 @@ separate memory range only intended for GPIO driving, and the register
 range dealing with pin config and pin multiplexing get placed into a
 different memory range and a separate section of the data sheet.
 
-A flag "strict" in struct pinctrl_desc is available to check and deny
+A flag "strict" in struct pinmux_ops is available to check and deny
 simultaneous access to the same pin from GPIO and pin multiplexing
 consumers on hardware of this type. The pinctrl driver should set this flag
 accordingly.
index c1739eb..febb29c 100644 (file)
@@ -5334,8 +5334,9 @@ M:        Bjorn Andersson <bjorn.andersson@linaro.org>
 L:     linux-remoteproc@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ohad/hwspinlock.git
+F:     Documentation/devicetree/bindings/hwlock/
 F:     Documentation/hwspinlock.txt
-F:     drivers/hwspinlock/hwspinlock_*
+F:     drivers/hwspinlock/
 F:     include/linux/hwspinlock.h
 
 HARMONY SOUND DRIVER
@@ -9732,8 +9733,9 @@ M:        Bjorn Andersson <bjorn.andersson@linaro.org>
 L:     linux-remoteproc@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ohad/remoteproc.git
 S:     Maintained
-F:     drivers/remoteproc/
+F:     Documentation/devicetree/bindings/remoteproc/
 F:     Documentation/remoteproc.txt
+F:     drivers/remoteproc/
 F:     include/linux/remoteproc.h
 
 REMOTE PROCESSOR MESSAGING (RPMSG) SUBSYSTEM
@@ -11440,11 +11442,6 @@ F:     Documentation/thermal/cpu-cooling-api.txt
 F:     drivers/thermal/cpu_cooling.c
 F:     include/linux/cpu_cooling.h
 
-THINGM BLINK(1) USB RGB LED DRIVER
-M:     Vivien Didelot <vivien.didelot@savoirfairelinux.com>
-S:     Maintained
-F:     drivers/hid/hid-thingm.c
-
 THINKPAD ACPI EXTRAS DRIVER
 M:     Henrique de Moraes Holschuh <ibm-acpi@hmh.eng.br>
 L:     ibm-acpi-devel@lists.sourceforge.net
index 781ef5f..021692c 100644 (file)
@@ -282,7 +282,7 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
  * These perform PCI memory accesses via an ioremap region.  They don't
  * take an address as such, but a cookie.
  *
- * Again, this are defined to perform little endian accesses.  See the
+ * Again, these are defined to perform little endian accesses.  See the
  * IO port primitives for more information.
  */
 #ifndef readl
index 2ade7a6..bbb7ee7 100644 (file)
@@ -224,7 +224,7 @@ void __init arm64_memblock_init(void)
         * via the linear mapping.
         */
        if (memory_limit != (phys_addr_t)ULLONG_MAX) {
-               memblock_enforce_memory_limit(memory_limit);
+               memblock_mem_limit_remove_map(memory_limit);
                memblock_add(__pa(_text), (u64)(_end - _text));
        }
 
index f9af646..9144204 100644 (file)
@@ -143,12 +143,12 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio)
  */
 static long
 axon_ram_direct_access(struct block_device *device, sector_t sector,
-                      void __pmem **kaddr, pfn_t *pfn, long size)
+                      void **kaddr, pfn_t *pfn, long size)
 {
        struct axon_ram_bank *bank = device->bd_disk->private_data;
        loff_t offset = (loff_t)sector << AXON_RAM_SECTOR_SHIFT;
 
-       *kaddr = (void __pmem __force *) bank->io_addr + offset;
+       *kaddr = (void *) bank->io_addr + offset;
        *pfn = phys_to_pfn_t(bank->ph_addr + offset, PFN_DEV);
        return bank->size - offset;
 }
index edcf2a7..598df57 100644 (file)
@@ -102,7 +102,7 @@ static void appldata_get_mem_data(void *data)
        mem_data->totalhigh = P2K(val.totalhigh);
        mem_data->freehigh  = P2K(val.freehigh);
        mem_data->bufferram = P2K(val.bufferram);
-       mem_data->cached    = P2K(global_page_state(NR_FILE_PAGES)
+       mem_data->cached    = P2K(global_node_page_state(NR_FILE_PAGES)
                                - val.bufferram);
 
        si_swapinfo(&val);
index c4d5bf8..7cc6ee7 100644 (file)
@@ -45,20 +45,20 @@ void show_mem(unsigned int filter)
        struct zone *zone;
 
        pr_err("Active:%lu inactive:%lu dirty:%lu writeback:%lu unstable:%lu free:%lu\n slab:%lu mapped:%lu pagetables:%lu bounce:%lu pagecache:%lu swap:%lu\n",
-              (global_page_state(NR_ACTIVE_ANON) +
-               global_page_state(NR_ACTIVE_FILE)),
-              (global_page_state(NR_INACTIVE_ANON) +
-               global_page_state(NR_INACTIVE_FILE)),
-              global_page_state(NR_FILE_DIRTY),
-              global_page_state(NR_WRITEBACK),
-              global_page_state(NR_UNSTABLE_NFS),
+              (global_node_page_state(NR_ACTIVE_ANON) +
+               global_node_page_state(NR_ACTIVE_FILE)),
+              (global_node_page_state(NR_INACTIVE_ANON) +
+               global_node_page_state(NR_INACTIVE_FILE)),
+              global_node_page_state(NR_FILE_DIRTY),
+              global_node_page_state(NR_WRITEBACK),
+              global_node_page_state(NR_UNSTABLE_NFS),
               global_page_state(NR_FREE_PAGES),
               (global_page_state(NR_SLAB_RECLAIMABLE) +
                global_page_state(NR_SLAB_UNRECLAIMABLE)),
-              global_page_state(NR_FILE_MAPPED),
+              global_node_page_state(NR_FILE_MAPPED),
               global_page_state(NR_PAGETABLE),
               global_page_state(NR_BOUNCE),
-              global_page_state(NR_FILE_PAGES),
+              global_node_page_state(NR_FILE_PAGES),
               get_nr_swap_pages());
 
        for_each_zone(zone) {
index c64b1e9..d683993 100644 (file)
 #define X86_FEATURE_RDSEED     ( 9*32+18) /* The RDSEED instruction */
 #define X86_FEATURE_ADX                ( 9*32+19) /* The ADCX and ADOX instructions */
 #define X86_FEATURE_SMAP       ( 9*32+20) /* Supervisor Mode Access Prevention */
-#define X86_FEATURE_PCOMMIT    ( 9*32+22) /* PCOMMIT instruction */
 #define X86_FEATURE_CLFLUSHOPT ( 9*32+23) /* CLFLUSHOPT instruction */
 #define X86_FEATURE_CLWB       ( 9*32+24) /* CLWB instruction */
 #define X86_FEATURE_AVX512PF   ( 9*32+26) /* AVX-512 Prefetch */
index fbc5e92..643eba4 100644 (file)
  * @n: length of the copy in bytes
  *
  * Copy data to persistent memory media via non-temporal stores so that
- * a subsequent arch_wmb_pmem() can flush cpu and memory controller
- * write buffers to guarantee durability.
+ * a subsequent pmem driver flush operation will drain posted write queues.
  */
-static inline void arch_memcpy_to_pmem(void __pmem *dst, const void *src,
-               size_t n)
+static inline void arch_memcpy_to_pmem(void *dst, const void *src, size_t n)
 {
-       int unwritten;
+       int rem;
 
        /*
         * We are copying between two kernel buffers, if
@@ -40,59 +38,36 @@ static inline void arch_memcpy_to_pmem(void __pmem *dst, const void *src,
         * fault) we would have already reported a general protection fault
         * before the WARN+BUG.
         */
-       unwritten = __copy_from_user_inatomic_nocache((void __force *) dst,
-                       (void __user *) src, n);
-       if (WARN(unwritten, "%s: fault copying %p <- %p unwritten: %d\n",
-                               __func__, dst, src, unwritten))
+       rem = __copy_from_user_inatomic_nocache(dst, (void __user *) src, n);
+       if (WARN(rem, "%s: fault copying %p <- %p unwritten: %d\n",
+                               __func__, dst, src, rem))
                BUG();
 }
 
-static inline int arch_memcpy_from_pmem(void *dst, const void __pmem *src,
-               size_t n)
+static inline int arch_memcpy_from_pmem(void *dst, const void *src, size_t n)
 {
        if (static_cpu_has(X86_FEATURE_MCE_RECOVERY))
-               return memcpy_mcsafe(dst, (void __force *) src, n);
-       memcpy(dst, (void __force *) src, n);
+               return memcpy_mcsafe(dst, src, n);
+       memcpy(dst, src, n);
        return 0;
 }
 
-/**
- * arch_wmb_pmem - synchronize writes to persistent memory
- *
- * After a series of arch_memcpy_to_pmem() operations this drains data
- * from cpu write buffers and any platform (memory controller) buffers
- * to ensure that written data is durable on persistent memory media.
- */
-static inline void arch_wmb_pmem(void)
-{
-       /*
-        * wmb() to 'sfence' all previous writes such that they are
-        * architecturally visible to 'pcommit'.  Note, that we've
-        * already arranged for pmem writes to avoid the cache via
-        * arch_memcpy_to_pmem().
-        */
-       wmb();
-       pcommit_sfence();
-}
-
 /**
  * arch_wb_cache_pmem - write back a cache range with CLWB
  * @vaddr:     virtual start address
  * @size:      number of bytes to write back
  *
  * Write back a cache range using the CLWB (cache line write back)
- * instruction.  This function requires explicit ordering with an
- * arch_wmb_pmem() call.
+ * instruction.
  */
-static inline void arch_wb_cache_pmem(void __pmem *addr, size_t size)
+static inline void arch_wb_cache_pmem(void *addr, size_t size)
 {
        u16 x86_clflush_size = boot_cpu_data.x86_clflush_size;
        unsigned long clflush_mask = x86_clflush_size - 1;
-       void *vaddr = (void __force *)addr;
-       void *vend = vaddr + size;
+       void *vend = addr + size;
        void *p;
 
-       for (p = (void *)((unsigned long)vaddr & ~clflush_mask);
+       for (p = (void *)((unsigned long)addr & ~clflush_mask);
             p < vend; p += x86_clflush_size)
                clwb(p);
 }
@@ -113,16 +88,14 @@ static inline bool __iter_needs_pmem_wb(struct iov_iter *i)
  * @i:         iterator with source data
  *
  * Copy data from the iterator 'i' to the PMEM buffer starting at 'addr'.
- * This function requires explicit ordering with an arch_wmb_pmem() call.
  */
-static inline size_t arch_copy_from_iter_pmem(void __pmem *addr, size_t bytes,
+static inline size_t arch_copy_from_iter_pmem(void *addr, size_t bytes,
                struct iov_iter *i)
 {
-       void *vaddr = (void __force *)addr;
        size_t len;
 
        /* TODO: skip the write-back by always using non-temporal stores */
-       len = copy_from_iter_nocache(vaddr, bytes, i);
+       len = copy_from_iter_nocache(addr, bytes, i);
 
        if (__iter_needs_pmem_wb(i))
                arch_wb_cache_pmem(addr, bytes);
@@ -136,28 +109,16 @@ static inline size_t arch_copy_from_iter_pmem(void __pmem *addr, size_t bytes,
  * @size:      number of bytes to zero
  *
  * Write zeros into the memory range starting at 'addr' for 'size' bytes.
- * This function requires explicit ordering with an arch_wmb_pmem() call.
  */
-static inline void arch_clear_pmem(void __pmem *addr, size_t size)
+static inline void arch_clear_pmem(void *addr, size_t size)
 {
-       void *vaddr = (void __force *)addr;
-
-       memset(vaddr, 0, size);
+       memset(addr, 0, size);
        arch_wb_cache_pmem(addr, size);
 }
 
-static inline void arch_invalidate_pmem(void __pmem *addr, size_t size)
+static inline void arch_invalidate_pmem(void *addr, size_t size)
 {
-       clflush_cache_range((void __force *) addr, size);
-}
-
-static inline bool __arch_has_wmb_pmem(void)
-{
-       /*
-        * We require that wmb() be an 'sfence', that is only guaranteed on
-        * 64-bit builds
-        */
-       return static_cpu_has(X86_FEATURE_PCOMMIT);
+       clflush_cache_range(addr, size);
 }
 #endif /* CONFIG_ARCH_HAS_PMEM_API */
 #endif /* __ASM_X86_PMEM_H__ */
index d96d043..587d791 100644 (file)
@@ -253,52 +253,6 @@ static inline void clwb(volatile void *__p)
                : [pax] "a" (p));
 }
 
-/**
- * pcommit_sfence() - persistent commit and fence
- *
- * The PCOMMIT instruction ensures that data that has been flushed from the
- * processor's cache hierarchy with CLWB, CLFLUSHOPT or CLFLUSH is accepted to
- * memory and is durable on the DIMM.  The primary use case for this is
- * persistent memory.
- *
- * This function shows how to properly use CLWB/CLFLUSHOPT/CLFLUSH and PCOMMIT
- * with appropriate fencing.
- *
- * Example:
- * void flush_and_commit_buffer(void *vaddr, unsigned int size)
- * {
- *         unsigned long clflush_mask = boot_cpu_data.x86_clflush_size - 1;
- *         void *vend = vaddr + size;
- *         void *p;
- *
- *         for (p = (void *)((unsigned long)vaddr & ~clflush_mask);
- *              p < vend; p += boot_cpu_data.x86_clflush_size)
- *                 clwb(p);
- *
- *         // SFENCE to order CLWB/CLFLUSHOPT/CLFLUSH cache flushes
- *         // MFENCE via mb() also works
- *         wmb();
- *
- *         // PCOMMIT and the required SFENCE for ordering
- *         pcommit_sfence();
- * }
- *
- * After this function completes the data pointed to by 'vaddr' has been
- * accepted to memory and will be durable if the 'vaddr' points to persistent
- * memory.
- *
- * PCOMMIT must always be ordered by an MFENCE or SFENCE, so to help simplify
- * things we include both the PCOMMIT and the required SFENCE in the
- * alternatives generated by pcommit_sfence().
- */
-static inline void pcommit_sfence(void)
-{
-       alternative(ASM_NOP7,
-                   ".byte 0x66, 0x0f, 0xae, 0xf8\n\t" /* pcommit */
-                   "sfence",
-                   X86_FEATURE_PCOMMIT);
-}
-
 #define nop() asm volatile ("nop")
 
 
index 14c63c7..a002b07 100644 (file)
@@ -72,7 +72,6 @@
 #define SECONDARY_EXEC_SHADOW_VMCS              0x00004000
 #define SECONDARY_EXEC_ENABLE_PML               0x00020000
 #define SECONDARY_EXEC_XSAVES                  0x00100000
-#define SECONDARY_EXEC_PCOMMIT                 0x00200000
 #define SECONDARY_EXEC_TSC_SCALING              0x02000000
 
 #define PIN_BASED_EXT_INTR_MASK                 0x00000001
index 5b15d94..37fee27 100644 (file)
@@ -78,7 +78,6 @@
 #define EXIT_REASON_PML_FULL            62
 #define EXIT_REASON_XSAVES              63
 #define EXIT_REASON_XRSTORS             64
-#define EXIT_REASON_PCOMMIT             65
 
 #define VMX_EXIT_REASONS \
        { EXIT_REASON_EXCEPTION_NMI,         "EXCEPTION_NMI" }, \
        { EXIT_REASON_INVVPID,               "INVVPID" }, \
        { EXIT_REASON_INVPCID,               "INVPCID" }, \
        { EXIT_REASON_XSAVES,                "XSAVES" }, \
-       { EXIT_REASON_XRSTORS,               "XRSTORS" }, \
-       { EXIT_REASON_PCOMMIT,               "PCOMMIT" }
+       { EXIT_REASON_XRSTORS,               "XRSTORS" }
 
 #define VMX_ABORT_SAVE_GUEST_MSR_FAIL        1
 #define VMX_ABORT_LOAD_HOST_MSR_FAIL         4
index 7597b42..6435653 100644 (file)
@@ -366,7 +366,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                F(FSGSBASE) | F(BMI1) | F(HLE) | F(AVX2) | F(SMEP) |
                F(BMI2) | F(ERMS) | f_invpcid | F(RTM) | f_mpx | F(RDSEED) |
                F(ADX) | F(SMAP) | F(AVX512F) | F(AVX512PF) | F(AVX512ER) |
-               F(AVX512CD) | F(CLFLUSHOPT) | F(CLWB) | F(PCOMMIT);
+               F(AVX512CD) | F(CLFLUSHOPT) | F(CLWB);
 
        /* cpuid 0xD.1.eax */
        const u32 kvm_cpuid_D_1_eax_x86_features =
index e17a74b..35058c2 100644 (file)
@@ -144,14 +144,6 @@ static inline bool guest_cpuid_has_rtm(struct kvm_vcpu *vcpu)
        return best && (best->ebx & bit(X86_FEATURE_RTM));
 }
 
-static inline bool guest_cpuid_has_pcommit(struct kvm_vcpu *vcpu)
-{
-       struct kvm_cpuid_entry2 *best;
-
-       best = kvm_find_cpuid_entry(vcpu, 7, 0);
-       return best && (best->ebx & bit(X86_FEATURE_PCOMMIT));
-}
-
 static inline bool guest_cpuid_has_rdtscp(struct kvm_vcpu *vcpu)
 {
        struct kvm_cpuid_entry2 *best;
index 7758680..df07a0a 100644 (file)
@@ -2707,8 +2707,7 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
                SECONDARY_EXEC_APIC_REGISTER_VIRT |
                SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY |
                SECONDARY_EXEC_WBINVD_EXITING |
-               SECONDARY_EXEC_XSAVES |
-               SECONDARY_EXEC_PCOMMIT;
+               SECONDARY_EXEC_XSAVES;
 
        if (enable_ept) {
                /* nested EPT: emulate EPT also to L1 */
@@ -3270,7 +3269,6 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
                        SECONDARY_EXEC_SHADOW_VMCS |
                        SECONDARY_EXEC_XSAVES |
                        SECONDARY_EXEC_ENABLE_PML |
-                       SECONDARY_EXEC_PCOMMIT |
                        SECONDARY_EXEC_TSC_SCALING;
                if (adjust_vmx_controls(min2, opt2,
                                        MSR_IA32_VMX_PROCBASED_CTLS2,
@@ -4858,9 +4856,6 @@ static u32 vmx_secondary_exec_control(struct vcpu_vmx *vmx)
        if (!enable_pml)
                exec_control &= ~SECONDARY_EXEC_ENABLE_PML;
 
-       /* Currently, we allow L1 guest to directly run pcommit instruction. */
-       exec_control &= ~SECONDARY_EXEC_PCOMMIT;
-
        return exec_control;
 }
 
@@ -4904,9 +4899,10 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
 
        vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, vmx_exec_control(vmx));
 
-       if (cpu_has_secondary_exec_ctrls())
+       if (cpu_has_secondary_exec_ctrls()) {
                vmcs_write32(SECONDARY_VM_EXEC_CONTROL,
                                vmx_secondary_exec_control(vmx));
+       }
 
        if (kvm_vcpu_apicv_active(&vmx->vcpu)) {
                vmcs_write64(EOI_EXIT_BITMAP0, 0);
@@ -7564,13 +7560,6 @@ static int handle_pml_full(struct kvm_vcpu *vcpu)
        return 1;
 }
 
-static int handle_pcommit(struct kvm_vcpu *vcpu)
-{
-       /* we never catch pcommit instruct for L1 guest. */
-       WARN_ON(1);
-       return 1;
-}
-
 /*
  * The exit handlers return 1 if the exit was handled fully and guest execution
  * may resume.  Otherwise they set the kvm_run parameter to indicate what needs
@@ -7621,7 +7610,6 @@ static int (*const kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = {
        [EXIT_REASON_XSAVES]                  = handle_xsaves,
        [EXIT_REASON_XRSTORS]                 = handle_xrstors,
        [EXIT_REASON_PML_FULL]                = handle_pml_full,
-       [EXIT_REASON_PCOMMIT]                 = handle_pcommit,
 };
 
 static const int kvm_vmx_max_exit_handlers =
@@ -7930,8 +7918,6 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu)
                 * the XSS exit bitmap in vmcs12.
                 */
                return nested_cpu_has2(vmcs12, SECONDARY_EXEC_XSAVES);
-       case EXIT_REASON_PCOMMIT:
-               return nested_cpu_has2(vmcs12, SECONDARY_EXEC_PCOMMIT);
        default:
                return true;
        }
@@ -9094,15 +9080,6 @@ static void vmx_cpuid_update(struct kvm_vcpu *vcpu)
 
        if (cpu_has_secondary_exec_ctrls())
                vmcs_set_secondary_exec_control(secondary_exec_ctl);
-
-       if (static_cpu_has(X86_FEATURE_PCOMMIT) && nested) {
-               if (guest_cpuid_has_pcommit(vcpu))
-                       vmx->nested.nested_vmx_secondary_ctls_high |=
-                               SECONDARY_EXEC_PCOMMIT;
-               else
-                       vmx->nested.nested_vmx_secondary_ctls_high &=
-                               ~SECONDARY_EXEC_PCOMMIT;
-       }
 }
 
 static void vmx_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry)
@@ -9715,8 +9692,7 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
                exec_control &= ~(SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES |
                                  SECONDARY_EXEC_RDTSCP |
                                  SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY |
-                                 SECONDARY_EXEC_APIC_REGISTER_VIRT |
-                                 SECONDARY_EXEC_PCOMMIT);
+                                 SECONDARY_EXEC_APIC_REGISTER_VIRT);
                if (nested_cpu_has(vmcs12,
                                CPU_BASED_ACTIVATE_SECONDARY_CONTROLS))
                        exec_control |= vmcs12->secondary_vm_exec_control;
index ec378cd..767be7c 100644 (file)
@@ -1012,7 +1012,7 @@ GrpTable: Grp15
 4: XSAVE
 5: XRSTOR | lfence (11B)
 6: XSAVEOPT | clwb (66) | mfence (11B)
-7: clflush | clflushopt (66) | sfence (11B) | pcommit (66),(11B)
+7: clflush | clflushopt (66) | sfence (11B)
 EndTable
 
 GrpTable: Grp16
index acad70a..aebd944 100644 (file)
@@ -454,32 +454,7 @@ config ACPI_REDUCED_HARDWARE_ONLY
 
          If you are unsure what to do, do not enable this option.
 
-config ACPI_NFIT
-       tristate "ACPI NVDIMM Firmware Interface Table (NFIT)"
-       depends on PHYS_ADDR_T_64BIT
-       depends on BLK_DEV
-       depends on ARCH_HAS_MMIO_FLUSH
-       select LIBNVDIMM
-       help
-         Infrastructure to probe ACPI 6 compliant platforms for
-         NVDIMMs (NFIT) and register a libnvdimm device tree.  In
-         addition to storage devices this also enables libnvdimm to pass
-         ACPI._DSM messages for platform/dimm configuration.
-
-         To compile this driver as a module, choose M here:
-         the module will be called nfit.
-
-config ACPI_NFIT_DEBUG
-       bool "NFIT DSM debug"
-       depends on ACPI_NFIT
-       depends on DYNAMIC_DEBUG
-       default n
-       help
-         Enabling this option causes the nfit driver to dump the
-         input and output buffers of _DSM operations on the ACPI0012
-         device and its children.  This can be very verbose, so leave
-         it disabled unless you are debugging a hardware / firmware
-         issue.
+source "drivers/acpi/nfit/Kconfig"
 
 source "drivers/acpi/apei/Kconfig"
 source "drivers/acpi/dptf/Kconfig"
index 88f54f0..35a6ccb 100644 (file)
@@ -69,7 +69,7 @@ obj-$(CONFIG_ACPI_PCI_SLOT)   += pci_slot.o
 obj-$(CONFIG_ACPI_PROCESSOR)   += processor.o
 obj-$(CONFIG_ACPI)             += container.o
 obj-$(CONFIG_ACPI_THERMAL)     += thermal.o
-obj-$(CONFIG_ACPI_NFIT)                += nfit.o
+obj-$(CONFIG_ACPI_NFIT)                += nfit/
 obj-$(CONFIG_ACPI)             += acpi_memhotplug.o
 obj-$(CONFIG_ACPI_HOTPLUG_IOAPIC) += ioapic.o
 obj-$(CONFIG_ACPI_BATTERY)     += battery.o
diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c
deleted file mode 100644 (file)
index 1f0e060..0000000
+++ /dev/null
@@ -1,2713 +0,0 @@
-/*
- * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- */
-#include <linux/list_sort.h>
-#include <linux/libnvdimm.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/ndctl.h>
-#include <linux/delay.h>
-#include <linux/list.h>
-#include <linux/acpi.h>
-#include <linux/sort.h>
-#include <linux/pmem.h>
-#include <linux/io.h>
-#include <linux/nd.h>
-#include <asm/cacheflush.h>
-#include "nfit.h"
-
-/*
- * For readq() and writeq() on 32-bit builds, the hi-lo, lo-hi order is
- * irrelevant.
- */
-#include <linux/io-64-nonatomic-hi-lo.h>
-
-static bool force_enable_dimms;
-module_param(force_enable_dimms, bool, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(force_enable_dimms, "Ignore _STA (ACPI DIMM device) status");
-
-static unsigned int scrub_timeout = NFIT_ARS_TIMEOUT;
-module_param(scrub_timeout, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(scrub_timeout, "Initial scrub timeout in seconds");
-
-/* after three payloads of overflow, it's dead jim */
-static unsigned int scrub_overflow_abort = 3;
-module_param(scrub_overflow_abort, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(scrub_overflow_abort,
-               "Number of times we overflow ARS results before abort");
-
-static bool disable_vendor_specific;
-module_param(disable_vendor_specific, bool, S_IRUGO);
-MODULE_PARM_DESC(disable_vendor_specific,
-               "Limit commands to the publicly specified set\n");
-
-static struct workqueue_struct *nfit_wq;
-
-struct nfit_table_prev {
-       struct list_head spas;
-       struct list_head memdevs;
-       struct list_head dcrs;
-       struct list_head bdws;
-       struct list_head idts;
-       struct list_head flushes;
-};
-
-static u8 nfit_uuid[NFIT_UUID_MAX][16];
-
-const u8 *to_nfit_uuid(enum nfit_uuids id)
-{
-       return nfit_uuid[id];
-}
-EXPORT_SYMBOL(to_nfit_uuid);
-
-static struct acpi_nfit_desc *to_acpi_nfit_desc(
-               struct nvdimm_bus_descriptor *nd_desc)
-{
-       return container_of(nd_desc, struct acpi_nfit_desc, nd_desc);
-}
-
-static struct acpi_device *to_acpi_dev(struct acpi_nfit_desc *acpi_desc)
-{
-       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
-
-       /*
-        * If provider == 'ACPI.NFIT' we can assume 'dev' is a struct
-        * acpi_device.
-        */
-       if (!nd_desc->provider_name
-                       || strcmp(nd_desc->provider_name, "ACPI.NFIT") != 0)
-               return NULL;
-
-       return to_acpi_device(acpi_desc->dev);
-}
-
-static int xlat_status(void *buf, unsigned int cmd)
-{
-       struct nd_cmd_clear_error *clear_err;
-       struct nd_cmd_ars_status *ars_status;
-       struct nd_cmd_ars_start *ars_start;
-       struct nd_cmd_ars_cap *ars_cap;
-       u16 flags;
-
-       switch (cmd) {
-       case ND_CMD_ARS_CAP:
-               ars_cap = buf;
-               if ((ars_cap->status & 0xffff) == NFIT_ARS_CAP_NONE)
-                       return -ENOTTY;
-
-               /* Command failed */
-               if (ars_cap->status & 0xffff)
-                       return -EIO;
-
-               /* No supported scan types for this range */
-               flags = ND_ARS_PERSISTENT | ND_ARS_VOLATILE;
-               if ((ars_cap->status >> 16 & flags) == 0)
-                       return -ENOTTY;
-               break;
-       case ND_CMD_ARS_START:
-               ars_start = buf;
-               /* ARS is in progress */
-               if ((ars_start->status & 0xffff) == NFIT_ARS_START_BUSY)
-                       return -EBUSY;
-
-               /* Command failed */
-               if (ars_start->status & 0xffff)
-                       return -EIO;
-               break;
-       case ND_CMD_ARS_STATUS:
-               ars_status = buf;
-               /* Command failed */
-               if (ars_status->status & 0xffff)
-                       return -EIO;
-               /* Check extended status (Upper two bytes) */
-               if (ars_status->status == NFIT_ARS_STATUS_DONE)
-                       return 0;
-
-               /* ARS is in progress */
-               if (ars_status->status == NFIT_ARS_STATUS_BUSY)
-                       return -EBUSY;
-
-               /* No ARS performed for the current boot */
-               if (ars_status->status == NFIT_ARS_STATUS_NONE)
-                       return -EAGAIN;
-
-               /*
-                * ARS interrupted, either we overflowed or some other
-                * agent wants the scan to stop.  If we didn't overflow
-                * then just continue with the returned results.
-                */
-               if (ars_status->status == NFIT_ARS_STATUS_INTR) {
-                       if (ars_status->flags & NFIT_ARS_F_OVERFLOW)
-                               return -ENOSPC;
-                       return 0;
-               }
-
-               /* Unknown status */
-               if (ars_status->status >> 16)
-                       return -EIO;
-               break;
-       case ND_CMD_CLEAR_ERROR:
-               clear_err = buf;
-               if (clear_err->status & 0xffff)
-                       return -EIO;
-               if (!clear_err->cleared)
-                       return -EIO;
-               if (clear_err->length > clear_err->cleared)
-                       return clear_err->cleared;
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
-               struct nvdimm *nvdimm, unsigned int cmd, void *buf,
-               unsigned int buf_len, int *cmd_rc)
-{
-       struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
-       union acpi_object in_obj, in_buf, *out_obj;
-       const struct nd_cmd_desc *desc = NULL;
-       struct device *dev = acpi_desc->dev;
-       struct nd_cmd_pkg *call_pkg = NULL;
-       const char *cmd_name, *dimm_name;
-       unsigned long cmd_mask, dsm_mask;
-       acpi_handle handle;
-       unsigned int func;
-       const u8 *uuid;
-       u32 offset;
-       int rc, i;
-
-       func = cmd;
-       if (cmd == ND_CMD_CALL) {
-               call_pkg = buf;
-               func = call_pkg->nd_command;
-       }
-
-       if (nvdimm) {
-               struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-               struct acpi_device *adev = nfit_mem->adev;
-
-               if (!adev)
-                       return -ENOTTY;
-               if (call_pkg && nfit_mem->family != call_pkg->nd_family)
-                       return -ENOTTY;
-
-               dimm_name = nvdimm_name(nvdimm);
-               cmd_name = nvdimm_cmd_name(cmd);
-               cmd_mask = nvdimm_cmd_mask(nvdimm);
-               dsm_mask = nfit_mem->dsm_mask;
-               desc = nd_cmd_dimm_desc(cmd);
-               uuid = to_nfit_uuid(nfit_mem->family);
-               handle = adev->handle;
-       } else {
-               struct acpi_device *adev = to_acpi_dev(acpi_desc);
-
-               cmd_name = nvdimm_bus_cmd_name(cmd);
-               cmd_mask = nd_desc->cmd_mask;
-               dsm_mask = cmd_mask;
-               desc = nd_cmd_bus_desc(cmd);
-               uuid = to_nfit_uuid(NFIT_DEV_BUS);
-               handle = adev->handle;
-               dimm_name = "bus";
-       }
-
-       if (!desc || (cmd && (desc->out_num + desc->in_num == 0)))
-               return -ENOTTY;
-
-       if (!test_bit(cmd, &cmd_mask) || !test_bit(func, &dsm_mask))
-               return -ENOTTY;
-
-       in_obj.type = ACPI_TYPE_PACKAGE;
-       in_obj.package.count = 1;
-       in_obj.package.elements = &in_buf;
-       in_buf.type = ACPI_TYPE_BUFFER;
-       in_buf.buffer.pointer = buf;
-       in_buf.buffer.length = 0;
-
-       /* libnvdimm has already validated the input envelope */
-       for (i = 0; i < desc->in_num; i++)
-               in_buf.buffer.length += nd_cmd_in_size(nvdimm, cmd, desc,
-                               i, buf);
-
-       if (call_pkg) {
-               /* skip over package wrapper */
-               in_buf.buffer.pointer = (void *) &call_pkg->nd_payload;
-               in_buf.buffer.length = call_pkg->nd_size_in;
-       }
-
-       if (IS_ENABLED(CONFIG_ACPI_NFIT_DEBUG)) {
-               dev_dbg(dev, "%s:%s cmd: %d: func: %d input length: %d\n",
-                               __func__, dimm_name, cmd, func,
-                               in_buf.buffer.length);
-               print_hex_dump_debug("nvdimm in  ", DUMP_PREFIX_OFFSET, 4, 4,
-                       in_buf.buffer.pointer,
-                       min_t(u32, 256, in_buf.buffer.length), true);
-       }
-
-       out_obj = acpi_evaluate_dsm(handle, uuid, 1, func, &in_obj);
-       if (!out_obj) {
-               dev_dbg(dev, "%s:%s _DSM failed cmd: %s\n", __func__, dimm_name,
-                               cmd_name);
-               return -EINVAL;
-       }
-
-       if (call_pkg) {
-               call_pkg->nd_fw_size = out_obj->buffer.length;
-               memcpy(call_pkg->nd_payload + call_pkg->nd_size_in,
-                       out_obj->buffer.pointer,
-                       min(call_pkg->nd_fw_size, call_pkg->nd_size_out));
-
-               ACPI_FREE(out_obj);
-               /*
-                * Need to support FW function w/o known size in advance.
-                * Caller can determine required size based upon nd_fw_size.
-                * If we return an error (like elsewhere) then caller wouldn't
-                * be able to rely upon data returned to make calculation.
-                */
-               return 0;
-       }
-
-       if (out_obj->package.type != ACPI_TYPE_BUFFER) {
-               dev_dbg(dev, "%s:%s unexpected output object type cmd: %s type: %d\n",
-                               __func__, dimm_name, cmd_name, out_obj->type);
-               rc = -EINVAL;
-               goto out;
-       }
-
-       if (IS_ENABLED(CONFIG_ACPI_NFIT_DEBUG)) {
-               dev_dbg(dev, "%s:%s cmd: %s output length: %d\n", __func__,
-                               dimm_name, cmd_name, out_obj->buffer.length);
-               print_hex_dump_debug(cmd_name, DUMP_PREFIX_OFFSET, 4,
-                               4, out_obj->buffer.pointer, min_t(u32, 128,
-                                       out_obj->buffer.length), true);
-       }
-
-       for (i = 0, offset = 0; i < desc->out_num; i++) {
-               u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i, buf,
-                               (u32 *) out_obj->buffer.pointer);
-
-               if (offset + out_size > out_obj->buffer.length) {
-                       dev_dbg(dev, "%s:%s output object underflow cmd: %s field: %d\n",
-                                       __func__, dimm_name, cmd_name, i);
-                       break;
-               }
-
-               if (in_buf.buffer.length + offset + out_size > buf_len) {
-                       dev_dbg(dev, "%s:%s output overrun cmd: %s field: %d\n",
-                                       __func__, dimm_name, cmd_name, i);
-                       rc = -ENXIO;
-                       goto out;
-               }
-               memcpy(buf + in_buf.buffer.length + offset,
-                               out_obj->buffer.pointer + offset, out_size);
-               offset += out_size;
-       }
-       if (offset + in_buf.buffer.length < buf_len) {
-               if (i >= 1) {
-                       /*
-                        * status valid, return the number of bytes left
-                        * unfilled in the output buffer
-                        */
-                       rc = buf_len - offset - in_buf.buffer.length;
-                       if (cmd_rc)
-                               *cmd_rc = xlat_status(buf, cmd);
-               } else {
-                       dev_err(dev, "%s:%s underrun cmd: %s buf_len: %d out_len: %d\n",
-                                       __func__, dimm_name, cmd_name, buf_len,
-                                       offset);
-                       rc = -ENXIO;
-               }
-       } else {
-               rc = 0;
-               if (cmd_rc)
-                       *cmd_rc = xlat_status(buf, cmd);
-       }
-
- out:
-       ACPI_FREE(out_obj);
-
-       return rc;
-}
-
-static const char *spa_type_name(u16 type)
-{
-       static const char *to_name[] = {
-               [NFIT_SPA_VOLATILE] = "volatile",
-               [NFIT_SPA_PM] = "pmem",
-               [NFIT_SPA_DCR] = "dimm-control-region",
-               [NFIT_SPA_BDW] = "block-data-window",
-               [NFIT_SPA_VDISK] = "volatile-disk",
-               [NFIT_SPA_VCD] = "volatile-cd",
-               [NFIT_SPA_PDISK] = "persistent-disk",
-               [NFIT_SPA_PCD] = "persistent-cd",
-
-       };
-
-       if (type > NFIT_SPA_PCD)
-               return "unknown";
-
-       return to_name[type];
-}
-
-static int nfit_spa_type(struct acpi_nfit_system_address *spa)
-{
-       int i;
-
-       for (i = 0; i < NFIT_UUID_MAX; i++)
-               if (memcmp(to_nfit_uuid(i), spa->range_guid, 16) == 0)
-                       return i;
-       return -1;
-}
-
-static bool add_spa(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_table_prev *prev,
-               struct acpi_nfit_system_address *spa)
-{
-       size_t length = min_t(size_t, sizeof(*spa), spa->header.length);
-       struct device *dev = acpi_desc->dev;
-       struct nfit_spa *nfit_spa;
-
-       list_for_each_entry(nfit_spa, &prev->spas, list) {
-               if (memcmp(nfit_spa->spa, spa, length) == 0) {
-                       list_move_tail(&nfit_spa->list, &acpi_desc->spas);
-                       return true;
-               }
-       }
-
-       nfit_spa = devm_kzalloc(dev, sizeof(*nfit_spa), GFP_KERNEL);
-       if (!nfit_spa)
-               return false;
-       INIT_LIST_HEAD(&nfit_spa->list);
-       nfit_spa->spa = spa;
-       list_add_tail(&nfit_spa->list, &acpi_desc->spas);
-       dev_dbg(dev, "%s: spa index: %d type: %s\n", __func__,
-                       spa->range_index,
-                       spa_type_name(nfit_spa_type(spa)));
-       return true;
-}
-
-static bool add_memdev(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_table_prev *prev,
-               struct acpi_nfit_memory_map *memdev)
-{
-       size_t length = min_t(size_t, sizeof(*memdev), memdev->header.length);
-       struct device *dev = acpi_desc->dev;
-       struct nfit_memdev *nfit_memdev;
-
-       list_for_each_entry(nfit_memdev, &prev->memdevs, list)
-               if (memcmp(nfit_memdev->memdev, memdev, length) == 0) {
-                       list_move_tail(&nfit_memdev->list, &acpi_desc->memdevs);
-                       return true;
-               }
-
-       nfit_memdev = devm_kzalloc(dev, sizeof(*nfit_memdev), GFP_KERNEL);
-       if (!nfit_memdev)
-               return false;
-       INIT_LIST_HEAD(&nfit_memdev->list);
-       nfit_memdev->memdev = memdev;
-       list_add_tail(&nfit_memdev->list, &acpi_desc->memdevs);
-       dev_dbg(dev, "%s: memdev handle: %#x spa: %d dcr: %d\n",
-                       __func__, memdev->device_handle, memdev->range_index,
-                       memdev->region_index);
-       return true;
-}
-
-static bool add_dcr(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_table_prev *prev,
-               struct acpi_nfit_control_region *dcr)
-{
-       size_t length = min_t(size_t, sizeof(*dcr), dcr->header.length);
-       struct device *dev = acpi_desc->dev;
-       struct nfit_dcr *nfit_dcr;
-
-       list_for_each_entry(nfit_dcr, &prev->dcrs, list)
-               if (memcmp(nfit_dcr->dcr, dcr, length) == 0) {
-                       list_move_tail(&nfit_dcr->list, &acpi_desc->dcrs);
-                       return true;
-               }
-
-       nfit_dcr = devm_kzalloc(dev, sizeof(*nfit_dcr), GFP_KERNEL);
-       if (!nfit_dcr)
-               return false;
-       INIT_LIST_HEAD(&nfit_dcr->list);
-       nfit_dcr->dcr = dcr;
-       list_add_tail(&nfit_dcr->list, &acpi_desc->dcrs);
-       dev_dbg(dev, "%s: dcr index: %d windows: %d\n", __func__,
-                       dcr->region_index, dcr->windows);
-       return true;
-}
-
-static bool add_bdw(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_table_prev *prev,
-               struct acpi_nfit_data_region *bdw)
-{
-       size_t length = min_t(size_t, sizeof(*bdw), bdw->header.length);
-       struct device *dev = acpi_desc->dev;
-       struct nfit_bdw *nfit_bdw;
-
-       list_for_each_entry(nfit_bdw, &prev->bdws, list)
-               if (memcmp(nfit_bdw->bdw, bdw, length) == 0) {
-                       list_move_tail(&nfit_bdw->list, &acpi_desc->bdws);
-                       return true;
-               }
-
-       nfit_bdw = devm_kzalloc(dev, sizeof(*nfit_bdw), GFP_KERNEL);
-       if (!nfit_bdw)
-               return false;
-       INIT_LIST_HEAD(&nfit_bdw->list);
-       nfit_bdw->bdw = bdw;
-       list_add_tail(&nfit_bdw->list, &acpi_desc->bdws);
-       dev_dbg(dev, "%s: bdw dcr: %d windows: %d\n", __func__,
-                       bdw->region_index, bdw->windows);
-       return true;
-}
-
-static bool add_idt(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_table_prev *prev,
-               struct acpi_nfit_interleave *idt)
-{
-       size_t length = min_t(size_t, sizeof(*idt), idt->header.length);
-       struct device *dev = acpi_desc->dev;
-       struct nfit_idt *nfit_idt;
-
-       list_for_each_entry(nfit_idt, &prev->idts, list)
-               if (memcmp(nfit_idt->idt, idt, length) == 0) {
-                       list_move_tail(&nfit_idt->list, &acpi_desc->idts);
-                       return true;
-               }
-
-       nfit_idt = devm_kzalloc(dev, sizeof(*nfit_idt), GFP_KERNEL);
-       if (!nfit_idt)
-               return false;
-       INIT_LIST_HEAD(&nfit_idt->list);
-       nfit_idt->idt = idt;
-       list_add_tail(&nfit_idt->list, &acpi_desc->idts);
-       dev_dbg(dev, "%s: idt index: %d num_lines: %d\n", __func__,
-                       idt->interleave_index, idt->line_count);
-       return true;
-}
-
-static bool add_flush(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_table_prev *prev,
-               struct acpi_nfit_flush_address *flush)
-{
-       size_t length = min_t(size_t, sizeof(*flush), flush->header.length);
-       struct device *dev = acpi_desc->dev;
-       struct nfit_flush *nfit_flush;
-
-       list_for_each_entry(nfit_flush, &prev->flushes, list)
-               if (memcmp(nfit_flush->flush, flush, length) == 0) {
-                       list_move_tail(&nfit_flush->list, &acpi_desc->flushes);
-                       return true;
-               }
-
-       nfit_flush = devm_kzalloc(dev, sizeof(*nfit_flush), GFP_KERNEL);
-       if (!nfit_flush)
-               return false;
-       INIT_LIST_HEAD(&nfit_flush->list);
-       nfit_flush->flush = flush;
-       list_add_tail(&nfit_flush->list, &acpi_desc->flushes);
-       dev_dbg(dev, "%s: nfit_flush handle: %d hint_count: %d\n", __func__,
-                       flush->device_handle, flush->hint_count);
-       return true;
-}
-
-static void *add_table(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_table_prev *prev, void *table, const void *end)
-{
-       struct device *dev = acpi_desc->dev;
-       struct acpi_nfit_header *hdr;
-       void *err = ERR_PTR(-ENOMEM);
-
-       if (table >= end)
-               return NULL;
-
-       hdr = table;
-       if (!hdr->length) {
-               dev_warn(dev, "found a zero length table '%d' parsing nfit\n",
-                       hdr->type);
-               return NULL;
-       }
-
-       switch (hdr->type) {
-       case ACPI_NFIT_TYPE_SYSTEM_ADDRESS:
-               if (!add_spa(acpi_desc, prev, table))
-                       return err;
-               break;
-       case ACPI_NFIT_TYPE_MEMORY_MAP:
-               if (!add_memdev(acpi_desc, prev, table))
-                       return err;
-               break;
-       case ACPI_NFIT_TYPE_CONTROL_REGION:
-               if (!add_dcr(acpi_desc, prev, table))
-                       return err;
-               break;
-       case ACPI_NFIT_TYPE_DATA_REGION:
-               if (!add_bdw(acpi_desc, prev, table))
-                       return err;
-               break;
-       case ACPI_NFIT_TYPE_INTERLEAVE:
-               if (!add_idt(acpi_desc, prev, table))
-                       return err;
-               break;
-       case ACPI_NFIT_TYPE_FLUSH_ADDRESS:
-               if (!add_flush(acpi_desc, prev, table))
-                       return err;
-               break;
-       case ACPI_NFIT_TYPE_SMBIOS:
-               dev_dbg(dev, "%s: smbios\n", __func__);
-               break;
-       default:
-               dev_err(dev, "unknown table '%d' parsing nfit\n", hdr->type);
-               break;
-       }
-
-       return table + hdr->length;
-}
-
-static void nfit_mem_find_spa_bdw(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_mem *nfit_mem)
-{
-       u32 device_handle = __to_nfit_memdev(nfit_mem)->device_handle;
-       u16 dcr = nfit_mem->dcr->region_index;
-       struct nfit_spa *nfit_spa;
-
-       list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
-               u16 range_index = nfit_spa->spa->range_index;
-               int type = nfit_spa_type(nfit_spa->spa);
-               struct nfit_memdev *nfit_memdev;
-
-               if (type != NFIT_SPA_BDW)
-                       continue;
-
-               list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
-                       if (nfit_memdev->memdev->range_index != range_index)
-                               continue;
-                       if (nfit_memdev->memdev->device_handle != device_handle)
-                               continue;
-                       if (nfit_memdev->memdev->region_index != dcr)
-                               continue;
-
-                       nfit_mem->spa_bdw = nfit_spa->spa;
-                       return;
-               }
-       }
-
-       dev_dbg(acpi_desc->dev, "SPA-BDW not found for SPA-DCR %d\n",
-                       nfit_mem->spa_dcr->range_index);
-       nfit_mem->bdw = NULL;
-}
-
-static void nfit_mem_init_bdw(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_mem *nfit_mem, struct acpi_nfit_system_address *spa)
-{
-       u16 dcr = __to_nfit_memdev(nfit_mem)->region_index;
-       struct nfit_memdev *nfit_memdev;
-       struct nfit_flush *nfit_flush;
-       struct nfit_bdw *nfit_bdw;
-       struct nfit_idt *nfit_idt;
-       u16 idt_idx, range_index;
-
-       list_for_each_entry(nfit_bdw, &acpi_desc->bdws, list) {
-               if (nfit_bdw->bdw->region_index != dcr)
-                       continue;
-               nfit_mem->bdw = nfit_bdw->bdw;
-               break;
-       }
-
-       if (!nfit_mem->bdw)
-               return;
-
-       nfit_mem_find_spa_bdw(acpi_desc, nfit_mem);
-
-       if (!nfit_mem->spa_bdw)
-               return;
-
-       range_index = nfit_mem->spa_bdw->range_index;
-       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
-               if (nfit_memdev->memdev->range_index != range_index ||
-                               nfit_memdev->memdev->region_index != dcr)
-                       continue;
-               nfit_mem->memdev_bdw = nfit_memdev->memdev;
-               idt_idx = nfit_memdev->memdev->interleave_index;
-               list_for_each_entry(nfit_idt, &acpi_desc->idts, list) {
-                       if (nfit_idt->idt->interleave_index != idt_idx)
-                               continue;
-                       nfit_mem->idt_bdw = nfit_idt->idt;
-                       break;
-               }
-
-               list_for_each_entry(nfit_flush, &acpi_desc->flushes, list) {
-                       if (nfit_flush->flush->device_handle !=
-                                       nfit_memdev->memdev->device_handle)
-                               continue;
-                       nfit_mem->nfit_flush = nfit_flush;
-                       break;
-               }
-               break;
-       }
-}
-
-static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
-               struct acpi_nfit_system_address *spa)
-{
-       struct nfit_mem *nfit_mem, *found;
-       struct nfit_memdev *nfit_memdev;
-       int type = nfit_spa_type(spa);
-
-       switch (type) {
-       case NFIT_SPA_DCR:
-       case NFIT_SPA_PM:
-               break;
-       default:
-               return 0;
-       }
-
-       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
-               struct nfit_dcr *nfit_dcr;
-               u32 device_handle;
-               u16 dcr;
-
-               if (nfit_memdev->memdev->range_index != spa->range_index)
-                       continue;
-               found = NULL;
-               dcr = nfit_memdev->memdev->region_index;
-               device_handle = nfit_memdev->memdev->device_handle;
-               list_for_each_entry(nfit_mem, &acpi_desc->dimms, list)
-                       if (__to_nfit_memdev(nfit_mem)->device_handle
-                                       == device_handle) {
-                               found = nfit_mem;
-                               break;
-                       }
-
-               if (found)
-                       nfit_mem = found;
-               else {
-                       nfit_mem = devm_kzalloc(acpi_desc->dev,
-                                       sizeof(*nfit_mem), GFP_KERNEL);
-                       if (!nfit_mem)
-                               return -ENOMEM;
-                       INIT_LIST_HEAD(&nfit_mem->list);
-                       nfit_mem->acpi_desc = acpi_desc;
-                       list_add(&nfit_mem->list, &acpi_desc->dimms);
-               }
-
-               list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) {
-                       if (nfit_dcr->dcr->region_index != dcr)
-                               continue;
-                       /*
-                        * Record the control region for the dimm.  For
-                        * the ACPI 6.1 case, where there are separate
-                        * control regions for the pmem vs blk
-                        * interfaces, be sure to record the extended
-                        * blk details.
-                        */
-                       if (!nfit_mem->dcr)
-                               nfit_mem->dcr = nfit_dcr->dcr;
-                       else if (nfit_mem->dcr->windows == 0
-                                       && nfit_dcr->dcr->windows)
-                               nfit_mem->dcr = nfit_dcr->dcr;
-                       break;
-               }
-
-               if (dcr && !nfit_mem->dcr) {
-                       dev_err(acpi_desc->dev, "SPA %d missing DCR %d\n",
-                                       spa->range_index, dcr);
-                       return -ENODEV;
-               }
-
-               if (type == NFIT_SPA_DCR) {
-                       struct nfit_idt *nfit_idt;
-                       u16 idt_idx;
-
-                       /* multiple dimms may share a SPA when interleaved */
-                       nfit_mem->spa_dcr = spa;
-                       nfit_mem->memdev_dcr = nfit_memdev->memdev;
-                       idt_idx = nfit_memdev->memdev->interleave_index;
-                       list_for_each_entry(nfit_idt, &acpi_desc->idts, list) {
-                               if (nfit_idt->idt->interleave_index != idt_idx)
-                                       continue;
-                               nfit_mem->idt_dcr = nfit_idt->idt;
-                               break;
-                       }
-                       nfit_mem_init_bdw(acpi_desc, nfit_mem, spa);
-               } else {
-                       /*
-                        * A single dimm may belong to multiple SPA-PM
-                        * ranges, record at least one in addition to
-                        * any SPA-DCR range.
-                        */
-                       nfit_mem->memdev_pmem = nfit_memdev->memdev;
-               }
-       }
-
-       return 0;
-}
-
-static int nfit_mem_cmp(void *priv, struct list_head *_a, struct list_head *_b)
-{
-       struct nfit_mem *a = container_of(_a, typeof(*a), list);
-       struct nfit_mem *b = container_of(_b, typeof(*b), list);
-       u32 handleA, handleB;
-
-       handleA = __to_nfit_memdev(a)->device_handle;
-       handleB = __to_nfit_memdev(b)->device_handle;
-       if (handleA < handleB)
-               return -1;
-       else if (handleA > handleB)
-               return 1;
-       return 0;
-}
-
-static int nfit_mem_init(struct acpi_nfit_desc *acpi_desc)
-{
-       struct nfit_spa *nfit_spa;
-
-       /*
-        * For each SPA-DCR or SPA-PMEM address range find its
-        * corresponding MEMDEV(s).  From each MEMDEV find the
-        * corresponding DCR.  Then, if we're operating on a SPA-DCR,
-        * try to find a SPA-BDW and a corresponding BDW that references
-        * the DCR.  Throw it all into an nfit_mem object.  Note, that
-        * BDWs are optional.
-        */
-       list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
-               int rc;
-
-               rc = nfit_mem_dcr_init(acpi_desc, nfit_spa->spa);
-               if (rc)
-                       return rc;
-       }
-
-       list_sort(NULL, &acpi_desc->dimms, nfit_mem_cmp);
-
-       return 0;
-}
-
-static ssize_t revision_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
-       struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
-       struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
-
-       return sprintf(buf, "%d\n", acpi_desc->acpi_header.revision);
-}
-static DEVICE_ATTR_RO(revision);
-
-static struct attribute *acpi_nfit_attributes[] = {
-       &dev_attr_revision.attr,
-       NULL,
-};
-
-static struct attribute_group acpi_nfit_attribute_group = {
-       .name = "nfit",
-       .attrs = acpi_nfit_attributes,
-};
-
-static const struct attribute_group *acpi_nfit_attribute_groups[] = {
-       &nvdimm_bus_attribute_group,
-       &acpi_nfit_attribute_group,
-       NULL,
-};
-
-static struct acpi_nfit_memory_map *to_nfit_memdev(struct device *dev)
-{
-       struct nvdimm *nvdimm = to_nvdimm(dev);
-       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-
-       return __to_nfit_memdev(nfit_mem);
-}
-
-static struct acpi_nfit_control_region *to_nfit_dcr(struct device *dev)
-{
-       struct nvdimm *nvdimm = to_nvdimm(dev);
-       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-
-       return nfit_mem->dcr;
-}
-
-static ssize_t handle_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_memory_map *memdev = to_nfit_memdev(dev);
-
-       return sprintf(buf, "%#x\n", memdev->device_handle);
-}
-static DEVICE_ATTR_RO(handle);
-
-static ssize_t phys_id_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_memory_map *memdev = to_nfit_memdev(dev);
-
-       return sprintf(buf, "%#x\n", memdev->physical_id);
-}
-static DEVICE_ATTR_RO(phys_id);
-
-static ssize_t vendor_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
-
-       return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->vendor_id));
-}
-static DEVICE_ATTR_RO(vendor);
-
-static ssize_t rev_id_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
-
-       return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->revision_id));
-}
-static DEVICE_ATTR_RO(rev_id);
-
-static ssize_t device_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
-
-       return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->device_id));
-}
-static DEVICE_ATTR_RO(device);
-
-static ssize_t subsystem_vendor_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
-
-       return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->subsystem_vendor_id));
-}
-static DEVICE_ATTR_RO(subsystem_vendor);
-
-static ssize_t subsystem_rev_id_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
-
-       return sprintf(buf, "0x%04x\n",
-                       be16_to_cpu(dcr->subsystem_revision_id));
-}
-static DEVICE_ATTR_RO(subsystem_rev_id);
-
-static ssize_t subsystem_device_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
-
-       return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->subsystem_device_id));
-}
-static DEVICE_ATTR_RO(subsystem_device);
-
-static int num_nvdimm_formats(struct nvdimm *nvdimm)
-{
-       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-       int formats = 0;
-
-       if (nfit_mem->memdev_pmem)
-               formats++;
-       if (nfit_mem->memdev_bdw)
-               formats++;
-       return formats;
-}
-
-static ssize_t format_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
-
-       return sprintf(buf, "0x%04x\n", le16_to_cpu(dcr->code));
-}
-static DEVICE_ATTR_RO(format);
-
-static ssize_t format1_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       u32 handle;
-       ssize_t rc = -ENXIO;
-       struct nfit_mem *nfit_mem;
-       struct nfit_memdev *nfit_memdev;
-       struct acpi_nfit_desc *acpi_desc;
-       struct nvdimm *nvdimm = to_nvdimm(dev);
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
-
-       nfit_mem = nvdimm_provider_data(nvdimm);
-       acpi_desc = nfit_mem->acpi_desc;
-       handle = to_nfit_memdev(dev)->device_handle;
-
-       /* assumes DIMMs have at most 2 published interface codes */
-       mutex_lock(&acpi_desc->init_mutex);
-       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
-               struct acpi_nfit_memory_map *memdev = nfit_memdev->memdev;
-               struct nfit_dcr *nfit_dcr;
-
-               if (memdev->device_handle != handle)
-                       continue;
-
-               list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) {
-                       if (nfit_dcr->dcr->region_index != memdev->region_index)
-                               continue;
-                       if (nfit_dcr->dcr->code == dcr->code)
-                               continue;
-                       rc = sprintf(buf, "0x%04x\n",
-                                       le16_to_cpu(nfit_dcr->dcr->code));
-                       break;
-               }
-               if (rc != ENXIO)
-                       break;
-       }
-       mutex_unlock(&acpi_desc->init_mutex);
-       return rc;
-}
-static DEVICE_ATTR_RO(format1);
-
-static ssize_t formats_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct nvdimm *nvdimm = to_nvdimm(dev);
-
-       return sprintf(buf, "%d\n", num_nvdimm_formats(nvdimm));
-}
-static DEVICE_ATTR_RO(formats);
-
-static ssize_t serial_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
-
-       return sprintf(buf, "0x%08x\n", be32_to_cpu(dcr->serial_number));
-}
-static DEVICE_ATTR_RO(serial);
-
-static ssize_t family_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct nvdimm *nvdimm = to_nvdimm(dev);
-       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-
-       if (nfit_mem->family < 0)
-               return -ENXIO;
-       return sprintf(buf, "%d\n", nfit_mem->family);
-}
-static DEVICE_ATTR_RO(family);
-
-static ssize_t dsm_mask_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct nvdimm *nvdimm = to_nvdimm(dev);
-       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-
-       if (nfit_mem->family < 0)
-               return -ENXIO;
-       return sprintf(buf, "%#lx\n", nfit_mem->dsm_mask);
-}
-static DEVICE_ATTR_RO(dsm_mask);
-
-static ssize_t flags_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       u16 flags = to_nfit_memdev(dev)->flags;
-
-       return sprintf(buf, "%s%s%s%s%s\n",
-               flags & ACPI_NFIT_MEM_SAVE_FAILED ? "save_fail " : "",
-               flags & ACPI_NFIT_MEM_RESTORE_FAILED ? "restore_fail " : "",
-               flags & ACPI_NFIT_MEM_FLUSH_FAILED ? "flush_fail " : "",
-               flags & ACPI_NFIT_MEM_NOT_ARMED ? "not_armed " : "",
-               flags & ACPI_NFIT_MEM_HEALTH_OBSERVED ? "smart_event " : "");
-}
-static DEVICE_ATTR_RO(flags);
-
-static ssize_t id_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
-
-       if (dcr->valid_fields & ACPI_NFIT_CONTROL_MFG_INFO_VALID)
-               return sprintf(buf, "%04x-%02x-%04x-%08x\n",
-                               be16_to_cpu(dcr->vendor_id),
-                               dcr->manufacturing_location,
-                               be16_to_cpu(dcr->manufacturing_date),
-                               be32_to_cpu(dcr->serial_number));
-       else
-               return sprintf(buf, "%04x-%08x\n",
-                               be16_to_cpu(dcr->vendor_id),
-                               be32_to_cpu(dcr->serial_number));
-}
-static DEVICE_ATTR_RO(id);
-
-static struct attribute *acpi_nfit_dimm_attributes[] = {
-       &dev_attr_handle.attr,
-       &dev_attr_phys_id.attr,
-       &dev_attr_vendor.attr,
-       &dev_attr_device.attr,
-       &dev_attr_rev_id.attr,
-       &dev_attr_subsystem_vendor.attr,
-       &dev_attr_subsystem_device.attr,
-       &dev_attr_subsystem_rev_id.attr,
-       &dev_attr_format.attr,
-       &dev_attr_formats.attr,
-       &dev_attr_format1.attr,
-       &dev_attr_serial.attr,
-       &dev_attr_flags.attr,
-       &dev_attr_id.attr,
-       &dev_attr_family.attr,
-       &dev_attr_dsm_mask.attr,
-       NULL,
-};
-
-static umode_t acpi_nfit_dimm_attr_visible(struct kobject *kobj,
-               struct attribute *a, int n)
-{
-       struct device *dev = container_of(kobj, struct device, kobj);
-       struct nvdimm *nvdimm = to_nvdimm(dev);
-
-       if (!to_nfit_dcr(dev))
-               return 0;
-       if (a == &dev_attr_format1.attr && num_nvdimm_formats(nvdimm) <= 1)
-               return 0;
-       return a->mode;
-}
-
-static struct attribute_group acpi_nfit_dimm_attribute_group = {
-       .name = "nfit",
-       .attrs = acpi_nfit_dimm_attributes,
-       .is_visible = acpi_nfit_dimm_attr_visible,
-};
-
-static const struct attribute_group *acpi_nfit_dimm_attribute_groups[] = {
-       &nvdimm_attribute_group,
-       &nd_device_attribute_group,
-       &acpi_nfit_dimm_attribute_group,
-       NULL,
-};
-
-static struct nvdimm *acpi_nfit_dimm_by_handle(struct acpi_nfit_desc *acpi_desc,
-               u32 device_handle)
-{
-       struct nfit_mem *nfit_mem;
-
-       list_for_each_entry(nfit_mem, &acpi_desc->dimms, list)
-               if (__to_nfit_memdev(nfit_mem)->device_handle == device_handle)
-                       return nfit_mem->nvdimm;
-
-       return NULL;
-}
-
-static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_mem *nfit_mem, u32 device_handle)
-{
-       struct acpi_device *adev, *adev_dimm;
-       struct device *dev = acpi_desc->dev;
-       unsigned long dsm_mask;
-       const u8 *uuid;
-       int i;
-
-       /* nfit test assumes 1:1 relationship between commands and dsms */
-       nfit_mem->dsm_mask = acpi_desc->dimm_cmd_force_en;
-       nfit_mem->family = NVDIMM_FAMILY_INTEL;
-       adev = to_acpi_dev(acpi_desc);
-       if (!adev)
-               return 0;
-
-       adev_dimm = acpi_find_child_device(adev, device_handle, false);
-       nfit_mem->adev = adev_dimm;
-       if (!adev_dimm) {
-               dev_err(dev, "no ACPI.NFIT device with _ADR %#x, disabling...\n",
-                               device_handle);
-               return force_enable_dimms ? 0 : -ENODEV;
-       }
-
-       /*
-        * Until standardization materializes we need to consider up to 3
-        * different command sets.  Note, that checking for function0 (bit0)
-        * tells us if any commands are reachable through this uuid.
-        */
-       for (i = NVDIMM_FAMILY_INTEL; i <= NVDIMM_FAMILY_HPE2; i++)
-               if (acpi_check_dsm(adev_dimm->handle, to_nfit_uuid(i), 1, 1))
-                       break;
-
-       /* limit the supported commands to those that are publicly documented */
-       nfit_mem->family = i;
-       if (nfit_mem->family == NVDIMM_FAMILY_INTEL) {
-               dsm_mask = 0x3fe;
-               if (disable_vendor_specific)
-                       dsm_mask &= ~(1 << ND_CMD_VENDOR);
-       } else if (nfit_mem->family == NVDIMM_FAMILY_HPE1)
-               dsm_mask = 0x1c3c76;
-       else if (nfit_mem->family == NVDIMM_FAMILY_HPE2) {
-               dsm_mask = 0x1fe;
-               if (disable_vendor_specific)
-                       dsm_mask &= ~(1 << 8);
-       } else {
-               dev_dbg(dev, "unknown dimm command family\n");
-               nfit_mem->family = -1;
-               /* DSMs are optional, continue loading the driver... */
-               return 0;
-       }
-
-       uuid = to_nfit_uuid(nfit_mem->family);
-       for_each_set_bit(i, &dsm_mask, BITS_PER_LONG)
-               if (acpi_check_dsm(adev_dimm->handle, uuid, 1, 1ULL << i))
-                       set_bit(i, &nfit_mem->dsm_mask);
-
-       return 0;
-}
-
-static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
-{
-       struct nfit_mem *nfit_mem;
-       int dimm_count = 0;
-
-       list_for_each_entry(nfit_mem, &acpi_desc->dimms, list) {
-               unsigned long flags = 0, cmd_mask;
-               struct nvdimm *nvdimm;
-               u32 device_handle;
-               u16 mem_flags;
-               int rc;
-
-               device_handle = __to_nfit_memdev(nfit_mem)->device_handle;
-               nvdimm = acpi_nfit_dimm_by_handle(acpi_desc, device_handle);
-               if (nvdimm) {
-                       dimm_count++;
-                       continue;
-               }
-
-               if (nfit_mem->bdw && nfit_mem->memdev_pmem)
-                       flags |= NDD_ALIASING;
-
-               mem_flags = __to_nfit_memdev(nfit_mem)->flags;
-               if (mem_flags & ACPI_NFIT_MEM_NOT_ARMED)
-                       flags |= NDD_UNARMED;
-
-               rc = acpi_nfit_add_dimm(acpi_desc, nfit_mem, device_handle);
-               if (rc)
-                       continue;
-
-               /*
-                * TODO: provide translation for non-NVDIMM_FAMILY_INTEL
-                * devices (i.e. from nd_cmd to acpi_dsm) to standardize the
-                * userspace interface.
-                */
-               cmd_mask = 1UL << ND_CMD_CALL;
-               if (nfit_mem->family == NVDIMM_FAMILY_INTEL)
-                       cmd_mask |= nfit_mem->dsm_mask;
-
-               nvdimm = nvdimm_create(acpi_desc->nvdimm_bus, nfit_mem,
-                               acpi_nfit_dimm_attribute_groups,
-                               flags, cmd_mask);
-               if (!nvdimm)
-                       return -ENOMEM;
-
-               nfit_mem->nvdimm = nvdimm;
-               dimm_count++;
-
-               if ((mem_flags & ACPI_NFIT_MEM_FAILED_MASK) == 0)
-                       continue;
-
-               dev_info(acpi_desc->dev, "%s flags:%s%s%s%s\n",
-                               nvdimm_name(nvdimm),
-                 mem_flags & ACPI_NFIT_MEM_SAVE_FAILED ? " save_fail" : "",
-                 mem_flags & ACPI_NFIT_MEM_RESTORE_FAILED ? " restore_fail":"",
-                 mem_flags & ACPI_NFIT_MEM_FLUSH_FAILED ? " flush_fail" : "",
-                 mem_flags & ACPI_NFIT_MEM_NOT_ARMED ? " not_armed" : "");
-
-       }
-
-       return nvdimm_bus_check_dimm_count(acpi_desc->nvdimm_bus, dimm_count);
-}
-
-static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc)
-{
-       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
-       const u8 *uuid = to_nfit_uuid(NFIT_DEV_BUS);
-       struct acpi_device *adev;
-       int i;
-
-       nd_desc->cmd_mask = acpi_desc->bus_cmd_force_en;
-       adev = to_acpi_dev(acpi_desc);
-       if (!adev)
-               return;
-
-       for (i = ND_CMD_ARS_CAP; i <= ND_CMD_CLEAR_ERROR; i++)
-               if (acpi_check_dsm(adev->handle, uuid, 1, 1ULL << i))
-                       set_bit(i, &nd_desc->cmd_mask);
-}
-
-static ssize_t range_index_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct nd_region *nd_region = to_nd_region(dev);
-       struct nfit_spa *nfit_spa = nd_region_provider_data(nd_region);
-
-       return sprintf(buf, "%d\n", nfit_spa->spa->range_index);
-}
-static DEVICE_ATTR_RO(range_index);
-
-static struct attribute *acpi_nfit_region_attributes[] = {
-       &dev_attr_range_index.attr,
-       NULL,
-};
-
-static struct attribute_group acpi_nfit_region_attribute_group = {
-       .name = "nfit",
-       .attrs = acpi_nfit_region_attributes,
-};
-
-static const struct attribute_group *acpi_nfit_region_attribute_groups[] = {
-       &nd_region_attribute_group,
-       &nd_mapping_attribute_group,
-       &nd_device_attribute_group,
-       &nd_numa_attribute_group,
-       &acpi_nfit_region_attribute_group,
-       NULL,
-};
-
-/* enough info to uniquely specify an interleave set */
-struct nfit_set_info {
-       struct nfit_set_info_map {
-               u64 region_offset;
-               u32 serial_number;
-               u32 pad;
-       } mapping[0];
-};
-
-static size_t sizeof_nfit_set_info(int num_mappings)
-{
-       return sizeof(struct nfit_set_info)
-               + num_mappings * sizeof(struct nfit_set_info_map);
-}
-
-static int cmp_map(const void *m0, const void *m1)
-{
-       const struct nfit_set_info_map *map0 = m0;
-       const struct nfit_set_info_map *map1 = m1;
-
-       return memcmp(&map0->region_offset, &map1->region_offset,
-                       sizeof(u64));
-}
-
-/* Retrieve the nth entry referencing this spa */
-static struct acpi_nfit_memory_map *memdev_from_spa(
-               struct acpi_nfit_desc *acpi_desc, u16 range_index, int n)
-{
-       struct nfit_memdev *nfit_memdev;
-
-       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list)
-               if (nfit_memdev->memdev->range_index == range_index)
-                       if (n-- == 0)
-                               return nfit_memdev->memdev;
-       return NULL;
-}
-
-static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc,
-               struct nd_region_desc *ndr_desc,
-               struct acpi_nfit_system_address *spa)
-{
-       int i, spa_type = nfit_spa_type(spa);
-       struct device *dev = acpi_desc->dev;
-       struct nd_interleave_set *nd_set;
-       u16 nr = ndr_desc->num_mappings;
-       struct nfit_set_info *info;
-
-       if (spa_type == NFIT_SPA_PM || spa_type == NFIT_SPA_VOLATILE)
-               /* pass */;
-       else
-               return 0;
-
-       nd_set = devm_kzalloc(dev, sizeof(*nd_set), GFP_KERNEL);
-       if (!nd_set)
-               return -ENOMEM;
-
-       info = devm_kzalloc(dev, sizeof_nfit_set_info(nr), GFP_KERNEL);
-       if (!info)
-               return -ENOMEM;
-       for (i = 0; i < nr; i++) {
-               struct nd_mapping *nd_mapping = &ndr_desc->nd_mapping[i];
-               struct nfit_set_info_map *map = &info->mapping[i];
-               struct nvdimm *nvdimm = nd_mapping->nvdimm;
-               struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-               struct acpi_nfit_memory_map *memdev = memdev_from_spa(acpi_desc,
-                               spa->range_index, i);
-
-               if (!memdev || !nfit_mem->dcr) {
-                       dev_err(dev, "%s: failed to find DCR\n", __func__);
-                       return -ENODEV;
-               }
-
-               map->region_offset = memdev->region_offset;
-               map->serial_number = nfit_mem->dcr->serial_number;
-       }
-
-       sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map),
-                       cmp_map, NULL);
-       nd_set->cookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0);
-       ndr_desc->nd_set = nd_set;
-       devm_kfree(dev, info);
-
-       return 0;
-}
-
-static u64 to_interleave_offset(u64 offset, struct nfit_blk_mmio *mmio)
-{
-       struct acpi_nfit_interleave *idt = mmio->idt;
-       u32 sub_line_offset, line_index, line_offset;
-       u64 line_no, table_skip_count, table_offset;
-
-       line_no = div_u64_rem(offset, mmio->line_size, &sub_line_offset);
-       table_skip_count = div_u64_rem(line_no, mmio->num_lines, &line_index);
-       line_offset = idt->line_offset[line_index]
-               * mmio->line_size;
-       table_offset = table_skip_count * mmio->table_size;
-
-       return mmio->base_offset + line_offset + table_offset + sub_line_offset;
-}
-
-static void wmb_blk(struct nfit_blk *nfit_blk)
-{
-
-       if (nfit_blk->nvdimm_flush) {
-               /*
-                * The first wmb() is needed to 'sfence' all previous writes
-                * such that they are architecturally visible for the platform
-                * buffer flush.  Note that we've already arranged for pmem
-                * writes to avoid the cache via arch_memcpy_to_pmem().  The
-                * final wmb() ensures ordering for the NVDIMM flush write.
-                */
-               wmb();
-               writeq(1, nfit_blk->nvdimm_flush);
-               wmb();
-       } else
-               wmb_pmem();
-}
-
-static u32 read_blk_stat(struct nfit_blk *nfit_blk, unsigned int bw)
-{
-       struct nfit_blk_mmio *mmio = &nfit_blk->mmio[DCR];
-       u64 offset = nfit_blk->stat_offset + mmio->size * bw;
-
-       if (mmio->num_lines)
-               offset = to_interleave_offset(offset, mmio);
-
-       return readl(mmio->addr.base + offset);
-}
-
-static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw,
-               resource_size_t dpa, unsigned int len, unsigned int write)
-{
-       u64 cmd, offset;
-       struct nfit_blk_mmio *mmio = &nfit_blk->mmio[DCR];
-
-       enum {
-               BCW_OFFSET_MASK = (1ULL << 48)-1,
-               BCW_LEN_SHIFT = 48,
-               BCW_LEN_MASK = (1ULL << 8) - 1,
-               BCW_CMD_SHIFT = 56,
-       };
-
-       cmd = (dpa >> L1_CACHE_SHIFT) & BCW_OFFSET_MASK;
-       len = len >> L1_CACHE_SHIFT;
-       cmd |= ((u64) len & BCW_LEN_MASK) << BCW_LEN_SHIFT;
-       cmd |= ((u64) write) << BCW_CMD_SHIFT;
-
-       offset = nfit_blk->cmd_offset + mmio->size * bw;
-       if (mmio->num_lines)
-               offset = to_interleave_offset(offset, mmio);
-
-       writeq(cmd, mmio->addr.base + offset);
-       wmb_blk(nfit_blk);
-
-       if (nfit_blk->dimm_flags & NFIT_BLK_DCR_LATCH)
-               readq(mmio->addr.base + offset);
-}
-
-static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk,
-               resource_size_t dpa, void *iobuf, size_t len, int rw,
-               unsigned int lane)
-{
-       struct nfit_blk_mmio *mmio = &nfit_blk->mmio[BDW];
-       unsigned int copied = 0;
-       u64 base_offset;
-       int rc;
-
-       base_offset = nfit_blk->bdw_offset + dpa % L1_CACHE_BYTES
-               + lane * mmio->size;
-       write_blk_ctl(nfit_blk, lane, dpa, len, rw);
-       while (len) {
-               unsigned int c;
-               u64 offset;
-
-               if (mmio->num_lines) {
-                       u32 line_offset;
-
-                       offset = to_interleave_offset(base_offset + copied,
-                                       mmio);
-                       div_u64_rem(offset, mmio->line_size, &line_offset);
-                       c = min_t(size_t, len, mmio->line_size - line_offset);
-               } else {
-                       offset = base_offset + nfit_blk->bdw_offset;
-                       c = len;
-               }
-
-               if (rw)
-                       memcpy_to_pmem(mmio->addr.aperture + offset,
-                                       iobuf + copied, c);
-               else {
-                       if (nfit_blk->dimm_flags & NFIT_BLK_READ_FLUSH)
-                               mmio_flush_range((void __force *)
-                                       mmio->addr.aperture + offset, c);
-
-                       memcpy_from_pmem(iobuf + copied,
-                                       mmio->addr.aperture + offset, c);
-               }
-
-               copied += c;
-               len -= c;
-       }
-
-       if (rw)
-               wmb_blk(nfit_blk);
-
-       rc = read_blk_stat(nfit_blk, lane) ? -EIO : 0;
-       return rc;
-}
-
-static int acpi_nfit_blk_region_do_io(struct nd_blk_region *ndbr,
-               resource_size_t dpa, void *iobuf, u64 len, int rw)
-{
-       struct nfit_blk *nfit_blk = nd_blk_region_provider_data(ndbr);
-       struct nfit_blk_mmio *mmio = &nfit_blk->mmio[BDW];
-       struct nd_region *nd_region = nfit_blk->nd_region;
-       unsigned int lane, copied = 0;
-       int rc = 0;
-
-       lane = nd_region_acquire_lane(nd_region);
-       while (len) {
-               u64 c = min(len, mmio->size);
-
-               rc = acpi_nfit_blk_single_io(nfit_blk, dpa + copied,
-                               iobuf + copied, c, rw, lane);
-               if (rc)
-                       break;
-
-               copied += c;
-               len -= c;
-       }
-       nd_region_release_lane(nd_region, lane);
-
-       return rc;
-}
-
-static void nfit_spa_mapping_release(struct kref *kref)
-{
-       struct nfit_spa_mapping *spa_map = to_spa_map(kref);
-       struct acpi_nfit_system_address *spa = spa_map->spa;
-       struct acpi_nfit_desc *acpi_desc = spa_map->acpi_desc;
-
-       WARN_ON(!mutex_is_locked(&acpi_desc->spa_map_mutex));
-       dev_dbg(acpi_desc->dev, "%s: SPA%d\n", __func__, spa->range_index);
-       if (spa_map->type == SPA_MAP_APERTURE)
-               memunmap((void __force *)spa_map->addr.aperture);
-       else
-               iounmap(spa_map->addr.base);
-       release_mem_region(spa->address, spa->length);
-       list_del(&spa_map->list);
-       kfree(spa_map);
-}
-
-static struct nfit_spa_mapping *find_spa_mapping(
-               struct acpi_nfit_desc *acpi_desc,
-               struct acpi_nfit_system_address *spa)
-{
-       struct nfit_spa_mapping *spa_map;
-
-       WARN_ON(!mutex_is_locked(&acpi_desc->spa_map_mutex));
-       list_for_each_entry(spa_map, &acpi_desc->spa_maps, list)
-               if (spa_map->spa == spa)
-                       return spa_map;
-
-       return NULL;
-}
-
-static void nfit_spa_unmap(struct acpi_nfit_desc *acpi_desc,
-               struct acpi_nfit_system_address *spa)
-{
-       struct nfit_spa_mapping *spa_map;
-
-       mutex_lock(&acpi_desc->spa_map_mutex);
-       spa_map = find_spa_mapping(acpi_desc, spa);
-
-       if (spa_map)
-               kref_put(&spa_map->kref, nfit_spa_mapping_release);
-       mutex_unlock(&acpi_desc->spa_map_mutex);
-}
-
-static void __iomem *__nfit_spa_map(struct acpi_nfit_desc *acpi_desc,
-               struct acpi_nfit_system_address *spa, enum spa_map_type type)
-{
-       resource_size_t start = spa->address;
-       resource_size_t n = spa->length;
-       struct nfit_spa_mapping *spa_map;
-       struct resource *res;
-
-       WARN_ON(!mutex_is_locked(&acpi_desc->spa_map_mutex));
-
-       spa_map = find_spa_mapping(acpi_desc, spa);
-       if (spa_map) {
-               kref_get(&spa_map->kref);
-               return spa_map->addr.base;
-       }
-
-       spa_map = kzalloc(sizeof(*spa_map), GFP_KERNEL);
-       if (!spa_map)
-               return NULL;
-
-       INIT_LIST_HEAD(&spa_map->list);
-       spa_map->spa = spa;
-       kref_init(&spa_map->kref);
-       spa_map->acpi_desc = acpi_desc;
-
-       res = request_mem_region(start, n, dev_name(acpi_desc->dev));
-       if (!res)
-               goto err_mem;
-
-       spa_map->type = type;
-       if (type == SPA_MAP_APERTURE)
-               spa_map->addr.aperture = (void __pmem *)memremap(start, n,
-                                                       ARCH_MEMREMAP_PMEM);
-       else
-               spa_map->addr.base = ioremap_nocache(start, n);
-
-
-       if (!spa_map->addr.base)
-               goto err_map;
-
-       list_add_tail(&spa_map->list, &acpi_desc->spa_maps);
-       return spa_map->addr.base;
-
- err_map:
-       release_mem_region(start, n);
- err_mem:
-       kfree(spa_map);
-       return NULL;
-}
-
-/**
- * nfit_spa_map - interleave-aware managed-mappings of acpi_nfit_system_address ranges
- * @nvdimm_bus: NFIT-bus that provided the spa table entry
- * @nfit_spa: spa table to map
- * @type: aperture or control region
- *
- * In the case where block-data-window apertures and
- * dimm-control-regions are interleaved they will end up sharing a
- * single request_mem_region() + ioremap() for the address range.  In
- * the style of devm nfit_spa_map() mappings are automatically dropped
- * when all region devices referencing the same mapping are disabled /
- * unbound.
- */
-static void __iomem *nfit_spa_map(struct acpi_nfit_desc *acpi_desc,
-               struct acpi_nfit_system_address *spa, enum spa_map_type type)
-{
-       void __iomem *iomem;
-
-       mutex_lock(&acpi_desc->spa_map_mutex);
-       iomem = __nfit_spa_map(acpi_desc, spa, type);
-       mutex_unlock(&acpi_desc->spa_map_mutex);
-
-       return iomem;
-}
-
-static int nfit_blk_init_interleave(struct nfit_blk_mmio *mmio,
-               struct acpi_nfit_interleave *idt, u16 interleave_ways)
-{
-       if (idt) {
-               mmio->num_lines = idt->line_count;
-               mmio->line_size = idt->line_size;
-               if (interleave_ways == 0)
-                       return -ENXIO;
-               mmio->table_size = mmio->num_lines * interleave_ways
-                       * mmio->line_size;
-       }
-
-       return 0;
-}
-
-static int acpi_nfit_blk_get_flags(struct nvdimm_bus_descriptor *nd_desc,
-               struct nvdimm *nvdimm, struct nfit_blk *nfit_blk)
-{
-       struct nd_cmd_dimm_flags flags;
-       int rc;
-
-       memset(&flags, 0, sizeof(flags));
-       rc = nd_desc->ndctl(nd_desc, nvdimm, ND_CMD_DIMM_FLAGS, &flags,
-                       sizeof(flags), NULL);
-
-       if (rc >= 0 && flags.status == 0)
-               nfit_blk->dimm_flags = flags.flags;
-       else if (rc == -ENOTTY) {
-               /* fall back to a conservative default */
-               nfit_blk->dimm_flags = NFIT_BLK_DCR_LATCH | NFIT_BLK_READ_FLUSH;
-               rc = 0;
-       } else
-               rc = -ENXIO;
-
-       return rc;
-}
-
-static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus,
-               struct device *dev)
-{
-       struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
-       struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
-       struct nd_blk_region *ndbr = to_nd_blk_region(dev);
-       struct nfit_flush *nfit_flush;
-       struct nfit_blk_mmio *mmio;
-       struct nfit_blk *nfit_blk;
-       struct nfit_mem *nfit_mem;
-       struct nvdimm *nvdimm;
-       int rc;
-
-       nvdimm = nd_blk_region_to_dimm(ndbr);
-       nfit_mem = nvdimm_provider_data(nvdimm);
-       if (!nfit_mem || !nfit_mem->dcr || !nfit_mem->bdw) {
-               dev_dbg(dev, "%s: missing%s%s%s\n", __func__,
-                               nfit_mem ? "" : " nfit_mem",
-                               (nfit_mem && nfit_mem->dcr) ? "" : " dcr",
-                               (nfit_mem && nfit_mem->bdw) ? "" : " bdw");
-               return -ENXIO;
-       }
-
-       nfit_blk = devm_kzalloc(dev, sizeof(*nfit_blk), GFP_KERNEL);
-       if (!nfit_blk)
-               return -ENOMEM;
-       nd_blk_region_set_provider_data(ndbr, nfit_blk);
-       nfit_blk->nd_region = to_nd_region(dev);
-
-       /* map block aperture memory */
-       nfit_blk->bdw_offset = nfit_mem->bdw->offset;
-       mmio = &nfit_blk->mmio[BDW];
-       mmio->addr.base = nfit_spa_map(acpi_desc, nfit_mem->spa_bdw,
-                       SPA_MAP_APERTURE);
-       if (!mmio->addr.base) {
-               dev_dbg(dev, "%s: %s failed to map bdw\n", __func__,
-                               nvdimm_name(nvdimm));
-               return -ENOMEM;
-       }
-       mmio->size = nfit_mem->bdw->size;
-       mmio->base_offset = nfit_mem->memdev_bdw->region_offset;
-       mmio->idt = nfit_mem->idt_bdw;
-       mmio->spa = nfit_mem->spa_bdw;
-       rc = nfit_blk_init_interleave(mmio, nfit_mem->idt_bdw,
-                       nfit_mem->memdev_bdw->interleave_ways);
-       if (rc) {
-               dev_dbg(dev, "%s: %s failed to init bdw interleave\n",
-                               __func__, nvdimm_name(nvdimm));
-               return rc;
-       }
-
-       /* map block control memory */
-       nfit_blk->cmd_offset = nfit_mem->dcr->command_offset;
-       nfit_blk->stat_offset = nfit_mem->dcr->status_offset;
-       mmio = &nfit_blk->mmio[DCR];
-       mmio->addr.base = nfit_spa_map(acpi_desc, nfit_mem->spa_dcr,
-                       SPA_MAP_CONTROL);
-       if (!mmio->addr.base) {
-               dev_dbg(dev, "%s: %s failed to map dcr\n", __func__,
-                               nvdimm_name(nvdimm));
-               return -ENOMEM;
-       }
-       mmio->size = nfit_mem->dcr->window_size;
-       mmio->base_offset = nfit_mem->memdev_dcr->region_offset;
-       mmio->idt = nfit_mem->idt_dcr;
-       mmio->spa = nfit_mem->spa_dcr;
-       rc = nfit_blk_init_interleave(mmio, nfit_mem->idt_dcr,
-                       nfit_mem->memdev_dcr->interleave_ways);
-       if (rc) {
-               dev_dbg(dev, "%s: %s failed to init dcr interleave\n",
-                               __func__, nvdimm_name(nvdimm));
-               return rc;
-       }
-
-       rc = acpi_nfit_blk_get_flags(nd_desc, nvdimm, nfit_blk);
-       if (rc < 0) {
-               dev_dbg(dev, "%s: %s failed get DIMM flags\n",
-                               __func__, nvdimm_name(nvdimm));
-               return rc;
-       }
-
-       nfit_flush = nfit_mem->nfit_flush;
-       if (nfit_flush && nfit_flush->flush->hint_count != 0) {
-               nfit_blk->nvdimm_flush = devm_ioremap_nocache(dev,
-                               nfit_flush->flush->hint_address[0], 8);
-               if (!nfit_blk->nvdimm_flush)
-                       return -ENOMEM;
-       }
-
-       if (!arch_has_wmb_pmem() && !nfit_blk->nvdimm_flush)
-               dev_warn(dev, "unable to guarantee persistence of writes\n");
-
-       if (mmio->line_size == 0)
-               return 0;
-
-       if ((u32) nfit_blk->cmd_offset % mmio->line_size
-                       + 8 > mmio->line_size) {
-               dev_dbg(dev, "cmd_offset crosses interleave boundary\n");
-               return -ENXIO;
-       } else if ((u32) nfit_blk->stat_offset % mmio->line_size
-                       + 8 > mmio->line_size) {
-               dev_dbg(dev, "stat_offset crosses interleave boundary\n");
-               return -ENXIO;
-       }
-
-       return 0;
-}
-
-static void acpi_nfit_blk_region_disable(struct nvdimm_bus *nvdimm_bus,
-               struct device *dev)
-{
-       struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
-       struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
-       struct nd_blk_region *ndbr = to_nd_blk_region(dev);
-       struct nfit_blk *nfit_blk = nd_blk_region_provider_data(ndbr);
-       int i;
-
-       if (!nfit_blk)
-               return; /* never enabled */
-
-       /* auto-free BLK spa mappings */
-       for (i = 0; i < 2; i++) {
-               struct nfit_blk_mmio *mmio = &nfit_blk->mmio[i];
-
-               if (mmio->addr.base)
-                       nfit_spa_unmap(acpi_desc, mmio->spa);
-       }
-       nd_blk_region_set_provider_data(ndbr, NULL);
-       /* devm will free nfit_blk */
-}
-
-static int ars_get_cap(struct acpi_nfit_desc *acpi_desc,
-               struct nd_cmd_ars_cap *cmd, struct nfit_spa *nfit_spa)
-{
-       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
-       struct acpi_nfit_system_address *spa = nfit_spa->spa;
-       int cmd_rc, rc;
-
-       cmd->address = spa->address;
-       cmd->length = spa->length;
-       rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_CAP, cmd,
-                       sizeof(*cmd), &cmd_rc);
-       if (rc < 0)
-               return rc;
-       return cmd_rc;
-}
-
-static int ars_start(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa)
-{
-       int rc;
-       int cmd_rc;
-       struct nd_cmd_ars_start ars_start;
-       struct acpi_nfit_system_address *spa = nfit_spa->spa;
-       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
-
-       memset(&ars_start, 0, sizeof(ars_start));
-       ars_start.address = spa->address;
-       ars_start.length = spa->length;
-       if (nfit_spa_type(spa) == NFIT_SPA_PM)
-               ars_start.type = ND_ARS_PERSISTENT;
-       else if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE)
-               ars_start.type = ND_ARS_VOLATILE;
-       else
-               return -ENOTTY;
-
-       rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_START, &ars_start,
-                       sizeof(ars_start), &cmd_rc);
-
-       if (rc < 0)
-               return rc;
-       return cmd_rc;
-}
-
-static int ars_continue(struct acpi_nfit_desc *acpi_desc)
-{
-       int rc, cmd_rc;
-       struct nd_cmd_ars_start ars_start;
-       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
-       struct nd_cmd_ars_status *ars_status = acpi_desc->ars_status;
-
-       memset(&ars_start, 0, sizeof(ars_start));
-       ars_start.address = ars_status->restart_address;
-       ars_start.length = ars_status->restart_length;
-       ars_start.type = ars_status->type;
-       rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_START, &ars_start,
-                       sizeof(ars_start), &cmd_rc);
-       if (rc < 0)
-               return rc;
-       return cmd_rc;
-}
-
-static int ars_get_status(struct acpi_nfit_desc *acpi_desc)
-{
-       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
-       struct nd_cmd_ars_status *ars_status = acpi_desc->ars_status;
-       int rc, cmd_rc;
-
-       rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_STATUS, ars_status,
-                       acpi_desc->ars_status_size, &cmd_rc);
-       if (rc < 0)
-               return rc;
-       return cmd_rc;
-}
-
-static int ars_status_process_records(struct nvdimm_bus *nvdimm_bus,
-               struct nd_cmd_ars_status *ars_status)
-{
-       int rc;
-       u32 i;
-
-       for (i = 0; i < ars_status->num_records; i++) {
-               rc = nvdimm_bus_add_poison(nvdimm_bus,
-                               ars_status->records[i].err_address,
-                               ars_status->records[i].length);
-               if (rc)
-                       return rc;
-       }
-
-       return 0;
-}
-
-static void acpi_nfit_remove_resource(void *data)
-{
-       struct resource *res = data;
-
-       remove_resource(res);
-}
-
-static int acpi_nfit_insert_resource(struct acpi_nfit_desc *acpi_desc,
-               struct nd_region_desc *ndr_desc)
-{
-       struct resource *res, *nd_res = ndr_desc->res;
-       int is_pmem, ret;
-
-       /* No operation if the region is already registered as PMEM */
-       is_pmem = region_intersects(nd_res->start, resource_size(nd_res),
-                               IORESOURCE_MEM, IORES_DESC_PERSISTENT_MEMORY);
-       if (is_pmem == REGION_INTERSECTS)
-               return 0;
-
-       res = devm_kzalloc(acpi_desc->dev, sizeof(*res), GFP_KERNEL);
-       if (!res)
-               return -ENOMEM;
-
-       res->name = "Persistent Memory";
-       res->start = nd_res->start;
-       res->end = nd_res->end;
-       res->flags = IORESOURCE_MEM;
-       res->desc = IORES_DESC_PERSISTENT_MEMORY;
-
-       ret = insert_resource(&iomem_resource, res);
-       if (ret)
-               return ret;
-
-       ret = devm_add_action(acpi_desc->dev, acpi_nfit_remove_resource, res);
-       if (ret) {
-               remove_resource(res);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int acpi_nfit_init_mapping(struct acpi_nfit_desc *acpi_desc,
-               struct nd_mapping *nd_mapping, struct nd_region_desc *ndr_desc,
-               struct acpi_nfit_memory_map *memdev,
-               struct nfit_spa *nfit_spa)
-{
-       struct nvdimm *nvdimm = acpi_nfit_dimm_by_handle(acpi_desc,
-                       memdev->device_handle);
-       struct acpi_nfit_system_address *spa = nfit_spa->spa;
-       struct nd_blk_region_desc *ndbr_desc;
-       struct nfit_mem *nfit_mem;
-       int blk_valid = 0;
-
-       if (!nvdimm) {
-               dev_err(acpi_desc->dev, "spa%d dimm: %#x not found\n",
-                               spa->range_index, memdev->device_handle);
-               return -ENODEV;
-       }
-
-       nd_mapping->nvdimm = nvdimm;
-       switch (nfit_spa_type(spa)) {
-       case NFIT_SPA_PM:
-       case NFIT_SPA_VOLATILE:
-               nd_mapping->start = memdev->address;
-               nd_mapping->size = memdev->region_size;
-               break;
-       case NFIT_SPA_DCR:
-               nfit_mem = nvdimm_provider_data(nvdimm);
-               if (!nfit_mem || !nfit_mem->bdw) {
-                       dev_dbg(acpi_desc->dev, "spa%d %s missing bdw\n",
-                                       spa->range_index, nvdimm_name(nvdimm));
-               } else {
-                       nd_mapping->size = nfit_mem->bdw->capacity;
-                       nd_mapping->start = nfit_mem->bdw->start_address;
-                       ndr_desc->num_lanes = nfit_mem->bdw->windows;
-                       blk_valid = 1;
-               }
-
-               ndr_desc->nd_mapping = nd_mapping;
-               ndr_desc->num_mappings = blk_valid;
-               ndbr_desc = to_blk_region_desc(ndr_desc);
-               ndbr_desc->enable = acpi_nfit_blk_region_enable;
-               ndbr_desc->disable = acpi_nfit_blk_region_disable;
-               ndbr_desc->do_io = acpi_desc->blk_do_io;
-               nfit_spa->nd_region = nvdimm_blk_region_create(acpi_desc->nvdimm_bus,
-                               ndr_desc);
-               if (!nfit_spa->nd_region)
-                       return -ENOMEM;
-               break;
-       }
-
-       return 0;
-}
-
-static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_spa *nfit_spa)
-{
-       static struct nd_mapping nd_mappings[ND_MAX_MAPPINGS];
-       struct acpi_nfit_system_address *spa = nfit_spa->spa;
-       struct nd_blk_region_desc ndbr_desc;
-       struct nd_region_desc *ndr_desc;
-       struct nfit_memdev *nfit_memdev;
-       struct nvdimm_bus *nvdimm_bus;
-       struct resource res;
-       int count = 0, rc;
-
-       if (nfit_spa->nd_region)
-               return 0;
-
-       if (spa->range_index == 0) {
-               dev_dbg(acpi_desc->dev, "%s: detected invalid spa index\n",
-                               __func__);
-               return 0;
-       }
-
-       memset(&res, 0, sizeof(res));
-       memset(&nd_mappings, 0, sizeof(nd_mappings));
-       memset(&ndbr_desc, 0, sizeof(ndbr_desc));
-       res.start = spa->address;
-       res.end = res.start + spa->length - 1;
-       ndr_desc = &ndbr_desc.ndr_desc;
-       ndr_desc->res = &res;
-       ndr_desc->provider_data = nfit_spa;
-       ndr_desc->attr_groups = acpi_nfit_region_attribute_groups;
-       if (spa->flags & ACPI_NFIT_PROXIMITY_VALID)
-               ndr_desc->numa_node = acpi_map_pxm_to_online_node(
-                                               spa->proximity_domain);
-       else
-               ndr_desc->numa_node = NUMA_NO_NODE;
-
-       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
-               struct acpi_nfit_memory_map *memdev = nfit_memdev->memdev;
-               struct nd_mapping *nd_mapping;
-
-               if (memdev->range_index != spa->range_index)
-                       continue;
-               if (count >= ND_MAX_MAPPINGS) {
-                       dev_err(acpi_desc->dev, "spa%d exceeds max mappings %d\n",
-                                       spa->range_index, ND_MAX_MAPPINGS);
-                       return -ENXIO;
-               }
-               nd_mapping = &nd_mappings[count++];
-               rc = acpi_nfit_init_mapping(acpi_desc, nd_mapping, ndr_desc,
-                               memdev, nfit_spa);
-               if (rc)
-                       goto out;
-       }
-
-       ndr_desc->nd_mapping = nd_mappings;
-       ndr_desc->num_mappings = count;
-       rc = acpi_nfit_init_interleave_set(acpi_desc, ndr_desc, spa);
-       if (rc)
-               goto out;
-
-       nvdimm_bus = acpi_desc->nvdimm_bus;
-       if (nfit_spa_type(spa) == NFIT_SPA_PM) {
-               rc = acpi_nfit_insert_resource(acpi_desc, ndr_desc);
-               if (rc) {
-                       dev_warn(acpi_desc->dev,
-                               "failed to insert pmem resource to iomem: %d\n",
-                               rc);
-                       goto out;
-               }
-
-               nfit_spa->nd_region = nvdimm_pmem_region_create(nvdimm_bus,
-                               ndr_desc);
-               if (!nfit_spa->nd_region)
-                       rc = -ENOMEM;
-       } else if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE) {
-               nfit_spa->nd_region = nvdimm_volatile_region_create(nvdimm_bus,
-                               ndr_desc);
-               if (!nfit_spa->nd_region)
-                       rc = -ENOMEM;
-       }
-
- out:
-       if (rc)
-               dev_err(acpi_desc->dev, "failed to register spa range %d\n",
-                               nfit_spa->spa->range_index);
-       return rc;
-}
-
-static int ars_status_alloc(struct acpi_nfit_desc *acpi_desc,
-               u32 max_ars)
-{
-       struct device *dev = acpi_desc->dev;
-       struct nd_cmd_ars_status *ars_status;
-
-       if (acpi_desc->ars_status && acpi_desc->ars_status_size >= max_ars) {
-               memset(acpi_desc->ars_status, 0, acpi_desc->ars_status_size);
-               return 0;
-       }
-
-       if (acpi_desc->ars_status)
-               devm_kfree(dev, acpi_desc->ars_status);
-       acpi_desc->ars_status = NULL;
-       ars_status = devm_kzalloc(dev, max_ars, GFP_KERNEL);
-       if (!ars_status)
-               return -ENOMEM;
-       acpi_desc->ars_status = ars_status;
-       acpi_desc->ars_status_size = max_ars;
-       return 0;
-}
-
-static int acpi_nfit_query_poison(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_spa *nfit_spa)
-{
-       struct acpi_nfit_system_address *spa = nfit_spa->spa;
-       int rc;
-
-       if (!nfit_spa->max_ars) {
-               struct nd_cmd_ars_cap ars_cap;
-
-               memset(&ars_cap, 0, sizeof(ars_cap));
-               rc = ars_get_cap(acpi_desc, &ars_cap, nfit_spa);
-               if (rc < 0)
-                       return rc;
-               nfit_spa->max_ars = ars_cap.max_ars_out;
-               nfit_spa->clear_err_unit = ars_cap.clear_err_unit;
-               /* check that the supported scrub types match the spa type */
-               if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE &&
-                               ((ars_cap.status >> 16) & ND_ARS_VOLATILE) == 0)
-                       return -ENOTTY;
-               else if (nfit_spa_type(spa) == NFIT_SPA_PM &&
-                               ((ars_cap.status >> 16) & ND_ARS_PERSISTENT) == 0)
-                       return -ENOTTY;
-       }
-
-       if (ars_status_alloc(acpi_desc, nfit_spa->max_ars))
-               return -ENOMEM;
-
-       rc = ars_get_status(acpi_desc);
-       if (rc < 0 && rc != -ENOSPC)
-               return rc;
-
-       if (ars_status_process_records(acpi_desc->nvdimm_bus,
-                               acpi_desc->ars_status))
-               return -ENOMEM;
-
-       return 0;
-}
-
-static void acpi_nfit_async_scrub(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_spa *nfit_spa)
-{
-       struct acpi_nfit_system_address *spa = nfit_spa->spa;
-       unsigned int overflow_retry = scrub_overflow_abort;
-       u64 init_ars_start = 0, init_ars_len = 0;
-       struct device *dev = acpi_desc->dev;
-       unsigned int tmo = scrub_timeout;
-       int rc;
-
-       if (nfit_spa->ars_done || !nfit_spa->nd_region)
-               return;
-
-       rc = ars_start(acpi_desc, nfit_spa);
-       /*
-        * If we timed out the initial scan we'll still be busy here,
-        * and will wait another timeout before giving up permanently.
-        */
-       if (rc < 0 && rc != -EBUSY)
-               return;
-
-       do {
-               u64 ars_start, ars_len;
-
-               if (acpi_desc->cancel)
-                       break;
-               rc = acpi_nfit_query_poison(acpi_desc, nfit_spa);
-               if (rc == -ENOTTY)
-                       break;
-               if (rc == -EBUSY && !tmo) {
-                       dev_warn(dev, "range %d ars timeout, aborting\n",
-                                       spa->range_index);
-                       break;
-               }
-
-               if (rc == -EBUSY) {
-                       /*
-                        * Note, entries may be appended to the list
-                        * while the lock is dropped, but the workqueue
-                        * being active prevents entries being deleted /
-                        * freed.
-                        */
-                       mutex_unlock(&acpi_desc->init_mutex);
-                       ssleep(1);
-                       tmo--;
-                       mutex_lock(&acpi_desc->init_mutex);
-                       continue;
-               }
-
-               /* we got some results, but there are more pending... */
-               if (rc == -ENOSPC && overflow_retry--) {
-                       if (!init_ars_len) {
-                               init_ars_len = acpi_desc->ars_status->length;
-                               init_ars_start = acpi_desc->ars_status->address;
-                       }
-                       rc = ars_continue(acpi_desc);
-               }
-
-               if (rc < 0) {
-                       dev_warn(dev, "range %d ars continuation failed\n",
-                                       spa->range_index);
-                       break;
-               }
-
-               if (init_ars_len) {
-                       ars_start = init_ars_start;
-                       ars_len = init_ars_len;
-               } else {
-                       ars_start = acpi_desc->ars_status->address;
-                       ars_len = acpi_desc->ars_status->length;
-               }
-               dev_dbg(dev, "spa range: %d ars from %#llx + %#llx complete\n",
-                               spa->range_index, ars_start, ars_len);
-               /* notify the region about new poison entries */
-               nvdimm_region_notify(nfit_spa->nd_region,
-                               NVDIMM_REVALIDATE_POISON);
-               break;
-       } while (1);
-}
-
-static void acpi_nfit_scrub(struct work_struct *work)
-{
-       struct device *dev;
-       u64 init_scrub_length = 0;
-       struct nfit_spa *nfit_spa;
-       u64 init_scrub_address = 0;
-       bool init_ars_done = false;
-       struct acpi_nfit_desc *acpi_desc;
-       unsigned int tmo = scrub_timeout;
-       unsigned int overflow_retry = scrub_overflow_abort;
-
-       acpi_desc = container_of(work, typeof(*acpi_desc), work);
-       dev = acpi_desc->dev;
-
-       /*
-        * We scrub in 2 phases.  The first phase waits for any platform
-        * firmware initiated scrubs to complete and then we go search for the
-        * affected spa regions to mark them scanned.  In the second phase we
-        * initiate a directed scrub for every range that was not scrubbed in
-        * phase 1.
-        */
-
-       /* process platform firmware initiated scrubs */
- retry:
-       mutex_lock(&acpi_desc->init_mutex);
-       list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
-               struct nd_cmd_ars_status *ars_status;
-               struct acpi_nfit_system_address *spa;
-               u64 ars_start, ars_len;
-               int rc;
-
-               if (acpi_desc->cancel)
-                       break;
-
-               if (nfit_spa->nd_region)
-                       continue;
-
-               if (init_ars_done) {
-                       /*
-                        * No need to re-query, we're now just
-                        * reconciling all the ranges covered by the
-                        * initial scrub
-                        */
-                       rc = 0;
-               } else
-                       rc = acpi_nfit_query_poison(acpi_desc, nfit_spa);
-
-               if (rc == -ENOTTY) {
-                       /* no ars capability, just register spa and move on */
-                       acpi_nfit_register_region(acpi_desc, nfit_spa);
-                       continue;
-               }
-
-               if (rc == -EBUSY && !tmo) {
-                       /* fallthrough to directed scrub in phase 2 */
-                       dev_warn(dev, "timeout awaiting ars results, continuing...\n");
-                       break;
-               } else if (rc == -EBUSY) {
-                       mutex_unlock(&acpi_desc->init_mutex);
-                       ssleep(1);
-                       tmo--;
-                       goto retry;
-               }
-
-               /* we got some results, but there are more pending... */
-               if (rc == -ENOSPC && overflow_retry--) {
-                       ars_status = acpi_desc->ars_status;
-                       /*
-                        * Record the original scrub range, so that we
-                        * can recall all the ranges impacted by the
-                        * initial scrub.
-                        */
-                       if (!init_scrub_length) {
-                               init_scrub_length = ars_status->length;
-                               init_scrub_address = ars_status->address;
-                       }
-                       rc = ars_continue(acpi_desc);
-                       if (rc == 0) {
-                               mutex_unlock(&acpi_desc->init_mutex);
-                               goto retry;
-                       }
-               }
-
-               if (rc < 0) {
-                       /*
-                        * Initial scrub failed, we'll give it one more
-                        * try below...
-                        */
-                       break;
-               }
-
-               /* We got some final results, record completed ranges */
-               ars_status = acpi_desc->ars_status;
-               if (init_scrub_length) {
-                       ars_start = init_scrub_address;
-                       ars_len = ars_start + init_scrub_length;
-               } else {
-                       ars_start = ars_status->address;
-                       ars_len = ars_status->length;
-               }
-               spa = nfit_spa->spa;
-
-               if (!init_ars_done) {
-                       init_ars_done = true;
-                       dev_dbg(dev, "init scrub %#llx + %#llx complete\n",
-                                       ars_start, ars_len);
-               }
-               if (ars_start <= spa->address && ars_start + ars_len
-                               >= spa->address + spa->length)
-                       acpi_nfit_register_region(acpi_desc, nfit_spa);
-       }
-
-       /*
-        * For all the ranges not covered by an initial scrub we still
-        * want to see if there are errors, but it's ok to discover them
-        * asynchronously.
-        */
-       list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
-               /*
-                * Flag all the ranges that still need scrubbing, but
-                * register them now to make data available.
-                */
-               if (nfit_spa->nd_region)
-                       nfit_spa->ars_done = 1;
-               else
-                       acpi_nfit_register_region(acpi_desc, nfit_spa);
-       }
-
-       list_for_each_entry(nfit_spa, &acpi_desc->spas, list)
-               acpi_nfit_async_scrub(acpi_desc, nfit_spa);
-       mutex_unlock(&acpi_desc->init_mutex);
-}
-
-static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc)
-{
-       struct nfit_spa *nfit_spa;
-       int rc;
-
-       list_for_each_entry(nfit_spa, &acpi_desc->spas, list)
-               if (nfit_spa_type(nfit_spa->spa) == NFIT_SPA_DCR) {
-                       /* BLK regions don't need to wait for ars results */
-                       rc = acpi_nfit_register_region(acpi_desc, nfit_spa);
-                       if (rc)
-                               return rc;
-               }
-
-       queue_work(nfit_wq, &acpi_desc->work);
-       return 0;
-}
-
-static int acpi_nfit_check_deletions(struct acpi_nfit_desc *acpi_desc,
-               struct nfit_table_prev *prev)
-{
-       struct device *dev = acpi_desc->dev;
-
-       if (!list_empty(&prev->spas) ||
-                       !list_empty(&prev->memdevs) ||
-                       !list_empty(&prev->dcrs) ||
-                       !list_empty(&prev->bdws) ||
-                       !list_empty(&prev->idts) ||
-                       !list_empty(&prev->flushes)) {
-               dev_err(dev, "new nfit deletes entries (unsupported)\n");
-               return -ENXIO;
-       }
-       return 0;
-}
-
-int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz)
-{
-       struct device *dev = acpi_desc->dev;
-       struct nfit_table_prev prev;
-       const void *end;
-       u8 *data;
-       int rc;
-
-       mutex_lock(&acpi_desc->init_mutex);
-
-       INIT_LIST_HEAD(&prev.spas);
-       INIT_LIST_HEAD(&prev.memdevs);
-       INIT_LIST_HEAD(&prev.dcrs);
-       INIT_LIST_HEAD(&prev.bdws);
-       INIT_LIST_HEAD(&prev.idts);
-       INIT_LIST_HEAD(&prev.flushes);
-
-       list_cut_position(&prev.spas, &acpi_desc->spas,
-                               acpi_desc->spas.prev);
-       list_cut_position(&prev.memdevs, &acpi_desc->memdevs,
-                               acpi_desc->memdevs.prev);
-       list_cut_position(&prev.dcrs, &acpi_desc->dcrs,
-                               acpi_desc->dcrs.prev);
-       list_cut_position(&prev.bdws, &acpi_desc->bdws,
-                               acpi_desc->bdws.prev);
-       list_cut_position(&prev.idts, &acpi_desc->idts,
-                               acpi_desc->idts.prev);
-       list_cut_position(&prev.flushes, &acpi_desc->flushes,
-                               acpi_desc->flushes.prev);
-
-       data = (u8 *) acpi_desc->nfit;
-       end = data + sz;
-       while (!IS_ERR_OR_NULL(data))
-               data = add_table(acpi_desc, &prev, data, end);
-
-       if (IS_ERR(data)) {
-               dev_dbg(dev, "%s: nfit table parsing error: %ld\n", __func__,
-                               PTR_ERR(data));
-               rc = PTR_ERR(data);
-               goto out_unlock;
-       }
-
-       rc = acpi_nfit_check_deletions(acpi_desc, &prev);
-       if (rc)
-               goto out_unlock;
-
-       if (nfit_mem_init(acpi_desc) != 0) {
-               rc = -ENOMEM;
-               goto out_unlock;
-       }
-
-       acpi_nfit_init_dsms(acpi_desc);
-
-       rc = acpi_nfit_register_dimms(acpi_desc);
-       if (rc)
-               goto out_unlock;
-
-       rc = acpi_nfit_register_regions(acpi_desc);
-
- out_unlock:
-       mutex_unlock(&acpi_desc->init_mutex);
-       return rc;
-}
-EXPORT_SYMBOL_GPL(acpi_nfit_init);
-
-struct acpi_nfit_flush_work {
-       struct work_struct work;
-       struct completion cmp;
-};
-
-static void flush_probe(struct work_struct *work)
-{
-       struct acpi_nfit_flush_work *flush;
-
-       flush = container_of(work, typeof(*flush), work);
-       complete(&flush->cmp);
-}
-
-static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc)
-{
-       struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
-       struct device *dev = acpi_desc->dev;
-       struct acpi_nfit_flush_work flush;
-
-       /* bounce the device lock to flush acpi_nfit_add / acpi_nfit_notify */
-       device_lock(dev);
-       device_unlock(dev);
-
-       /*
-        * Scrub work could take 10s of seconds, userspace may give up so we
-        * need to be interruptible while waiting.
-        */
-       INIT_WORK_ONSTACK(&flush.work, flush_probe);
-       COMPLETION_INITIALIZER_ONSTACK(flush.cmp);
-       queue_work(nfit_wq, &flush.work);
-       return wait_for_completion_interruptible(&flush.cmp);
-}
-
-static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
-               struct nvdimm *nvdimm, unsigned int cmd)
-{
-       struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
-
-       if (nvdimm)
-               return 0;
-       if (cmd != ND_CMD_ARS_START)
-               return 0;
-
-       /*
-        * The kernel and userspace may race to initiate a scrub, but
-        * the scrub thread is prepared to lose that initial race.  It
-        * just needs guarantees that any ars it initiates are not
-        * interrupted by any intervening start reqeusts from userspace.
-        */
-       if (work_busy(&acpi_desc->work))
-               return -EBUSY;
-
-       return 0;
-}
-
-void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev)
-{
-       struct nvdimm_bus_descriptor *nd_desc;
-
-       dev_set_drvdata(dev, acpi_desc);
-       acpi_desc->dev = dev;
-       acpi_desc->blk_do_io = acpi_nfit_blk_region_do_io;
-       nd_desc = &acpi_desc->nd_desc;
-       nd_desc->provider_name = "ACPI.NFIT";
-       nd_desc->ndctl = acpi_nfit_ctl;
-       nd_desc->flush_probe = acpi_nfit_flush_probe;
-       nd_desc->clear_to_send = acpi_nfit_clear_to_send;
-       nd_desc->attr_groups = acpi_nfit_attribute_groups;
-
-       INIT_LIST_HEAD(&acpi_desc->spa_maps);
-       INIT_LIST_HEAD(&acpi_desc->spas);
-       INIT_LIST_HEAD(&acpi_desc->dcrs);
-       INIT_LIST_HEAD(&acpi_desc->bdws);
-       INIT_LIST_HEAD(&acpi_desc->idts);
-       INIT_LIST_HEAD(&acpi_desc->flushes);
-       INIT_LIST_HEAD(&acpi_desc->memdevs);
-       INIT_LIST_HEAD(&acpi_desc->dimms);
-       mutex_init(&acpi_desc->spa_map_mutex);
-       mutex_init(&acpi_desc->init_mutex);
-       INIT_WORK(&acpi_desc->work, acpi_nfit_scrub);
-}
-EXPORT_SYMBOL_GPL(acpi_nfit_desc_init);
-
-static int acpi_nfit_add(struct acpi_device *adev)
-{
-       struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
-       struct acpi_nfit_desc *acpi_desc;
-       struct device *dev = &adev->dev;
-       struct acpi_table_header *tbl;
-       acpi_status status = AE_OK;
-       acpi_size sz;
-       int rc;
-
-       status = acpi_get_table_with_size(ACPI_SIG_NFIT, 0, &tbl, &sz);
-       if (ACPI_FAILURE(status)) {
-               /* This is ok, we could have an nvdimm hotplugged later */
-               dev_dbg(dev, "failed to find NFIT at startup\n");
-               return 0;
-       }
-
-       acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL);
-       if (!acpi_desc)
-               return -ENOMEM;
-       acpi_nfit_desc_init(acpi_desc, &adev->dev);
-       acpi_desc->nvdimm_bus = nvdimm_bus_register(dev, &acpi_desc->nd_desc);
-       if (!acpi_desc->nvdimm_bus)
-               return -ENOMEM;
-
-       /*
-        * Save the acpi header for later and then skip it,
-        * making nfit point to the first nfit table header.
-        */
-       acpi_desc->acpi_header = *tbl;
-       acpi_desc->nfit = (void *) tbl + sizeof(struct acpi_table_nfit);
-       sz -= sizeof(struct acpi_table_nfit);
-
-       /* Evaluate _FIT and override with that if present */
-       status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf);
-       if (ACPI_SUCCESS(status) && buf.length > 0) {
-               union acpi_object *obj;
-               /*
-                * Adjust for the acpi_object header of the _FIT
-                */
-               obj = buf.pointer;
-               if (obj->type == ACPI_TYPE_BUFFER) {
-                       acpi_desc->nfit =
-                               (struct acpi_nfit_header *)obj->buffer.pointer;
-                       sz = obj->buffer.length;
-               } else
-                       dev_dbg(dev, "%s invalid type %d, ignoring _FIT\n",
-                                __func__, (int) obj->type);
-       }
-
-       rc = acpi_nfit_init(acpi_desc, sz);
-       if (rc) {
-               nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
-               return rc;
-       }
-       return 0;
-}
-
-static int acpi_nfit_remove(struct acpi_device *adev)
-{
-       struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(&adev->dev);
-
-       acpi_desc->cancel = 1;
-       flush_workqueue(nfit_wq);
-       nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
-       return 0;
-}
-
-static void acpi_nfit_notify(struct acpi_device *adev, u32 event)
-{
-       struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(&adev->dev);
-       struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
-       struct acpi_nfit_header *nfit_saved;
-       union acpi_object *obj;
-       struct device *dev = &adev->dev;
-       acpi_status status;
-       int ret;
-
-       dev_dbg(dev, "%s: event: %d\n", __func__, event);
-
-       device_lock(dev);
-       if (!dev->driver) {
-               /* dev->driver may be null if we're being removed */
-               dev_dbg(dev, "%s: no driver found for dev\n", __func__);
-               goto out_unlock;
-       }
-
-       if (!acpi_desc) {
-               acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL);
-               if (!acpi_desc)
-                       goto out_unlock;
-               acpi_nfit_desc_init(acpi_desc, &adev->dev);
-               acpi_desc->nvdimm_bus = nvdimm_bus_register(dev, &acpi_desc->nd_desc);
-               if (!acpi_desc->nvdimm_bus)
-                       goto out_unlock;
-       } else {
-               /*
-                * Finish previous registration before considering new
-                * regions.
-                */
-               flush_workqueue(nfit_wq);
-       }
-
-       /* Evaluate _FIT */
-       status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf);
-       if (ACPI_FAILURE(status)) {
-               dev_err(dev, "failed to evaluate _FIT\n");
-               goto out_unlock;
-       }
-
-       nfit_saved = acpi_desc->nfit;
-       obj = buf.pointer;
-       if (obj->type == ACPI_TYPE_BUFFER) {
-               acpi_desc->nfit =
-                       (struct acpi_nfit_header *)obj->buffer.pointer;
-               ret = acpi_nfit_init(acpi_desc, obj->buffer.length);
-               if (ret) {
-                       /* Merge failed, restore old nfit, and exit */
-                       acpi_desc->nfit = nfit_saved;
-                       dev_err(dev, "failed to merge updated NFIT\n");
-               }
-       } else {
-               /* Bad _FIT, restore old nfit */
-               dev_err(dev, "Invalid _FIT\n");
-       }
-       kfree(buf.pointer);
-
- out_unlock:
-       device_unlock(dev);
-}
-
-static const struct acpi_device_id acpi_nfit_ids[] = {
-       { "ACPI0012", 0 },
-       { "", 0 },
-};
-MODULE_DEVICE_TABLE(acpi, acpi_nfit_ids);
-
-static struct acpi_driver acpi_nfit_driver = {
-       .name = KBUILD_MODNAME,
-       .ids = acpi_nfit_ids,
-       .ops = {
-               .add = acpi_nfit_add,
-               .remove = acpi_nfit_remove,
-               .notify = acpi_nfit_notify,
-       },
-};
-
-static __init int nfit_init(void)
-{
-       BUILD_BUG_ON(sizeof(struct acpi_table_nfit) != 40);
-       BUILD_BUG_ON(sizeof(struct acpi_nfit_system_address) != 56);
-       BUILD_BUG_ON(sizeof(struct acpi_nfit_memory_map) != 48);
-       BUILD_BUG_ON(sizeof(struct acpi_nfit_interleave) != 20);
-       BUILD_BUG_ON(sizeof(struct acpi_nfit_smbios) != 9);
-       BUILD_BUG_ON(sizeof(struct acpi_nfit_control_region) != 80);
-       BUILD_BUG_ON(sizeof(struct acpi_nfit_data_region) != 40);
-
-       acpi_str_to_uuid(UUID_VOLATILE_MEMORY, nfit_uuid[NFIT_SPA_VOLATILE]);
-       acpi_str_to_uuid(UUID_PERSISTENT_MEMORY, nfit_uuid[NFIT_SPA_PM]);
-       acpi_str_to_uuid(UUID_CONTROL_REGION, nfit_uuid[NFIT_SPA_DCR]);
-       acpi_str_to_uuid(UUID_DATA_REGION, nfit_uuid[NFIT_SPA_BDW]);
-       acpi_str_to_uuid(UUID_VOLATILE_VIRTUAL_DISK, nfit_uuid[NFIT_SPA_VDISK]);
-       acpi_str_to_uuid(UUID_VOLATILE_VIRTUAL_CD, nfit_uuid[NFIT_SPA_VCD]);
-       acpi_str_to_uuid(UUID_PERSISTENT_VIRTUAL_DISK, nfit_uuid[NFIT_SPA_PDISK]);
-       acpi_str_to_uuid(UUID_PERSISTENT_VIRTUAL_CD, nfit_uuid[NFIT_SPA_PCD]);
-       acpi_str_to_uuid(UUID_NFIT_BUS, nfit_uuid[NFIT_DEV_BUS]);
-       acpi_str_to_uuid(UUID_NFIT_DIMM, nfit_uuid[NFIT_DEV_DIMM]);
-       acpi_str_to_uuid(UUID_NFIT_DIMM_N_HPE1, nfit_uuid[NFIT_DEV_DIMM_N_HPE1]);
-       acpi_str_to_uuid(UUID_NFIT_DIMM_N_HPE2, nfit_uuid[NFIT_DEV_DIMM_N_HPE2]);
-
-       nfit_wq = create_singlethread_workqueue("nfit");
-       if (!nfit_wq)
-               return -ENOMEM;
-
-       return acpi_bus_register_driver(&acpi_nfit_driver);
-}
-
-static __exit void nfit_exit(void)
-{
-       acpi_bus_unregister_driver(&acpi_nfit_driver);
-       destroy_workqueue(nfit_wq);
-}
-
-module_init(nfit_init);
-module_exit(nfit_exit);
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Intel Corporation");
diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h
deleted file mode 100644 (file)
index 02b9ea1..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * NVDIMM Firmware Interface Table - NFIT
- *
- * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- */
-#ifndef __NFIT_H__
-#define __NFIT_H__
-#include <linux/workqueue.h>
-#include <linux/libnvdimm.h>
-#include <linux/types.h>
-#include <linux/uuid.h>
-#include <linux/acpi.h>
-#include <acpi/acuuid.h>
-
-/* ACPI 6.1 */
-#define UUID_NFIT_BUS "2f10e7a4-9e91-11e4-89d3-123b93f75cba"
-
-/* http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf */
-#define UUID_NFIT_DIMM "4309ac30-0d11-11e4-9191-0800200c9a66"
-
-/* https://github.com/HewlettPackard/hpe-nvm/blob/master/Documentation/ */
-#define UUID_NFIT_DIMM_N_HPE1 "9002c334-acf3-4c0e-9642-a235f0d53bc6"
-#define UUID_NFIT_DIMM_N_HPE2 "5008664b-b758-41a0-a03c-27c2f2d04f7e"
-
-#define ACPI_NFIT_MEM_FAILED_MASK (ACPI_NFIT_MEM_SAVE_FAILED \
-               | ACPI_NFIT_MEM_RESTORE_FAILED | ACPI_NFIT_MEM_FLUSH_FAILED \
-               | ACPI_NFIT_MEM_NOT_ARMED)
-
-enum nfit_uuids {
-       /* for simplicity alias the uuid index with the family id */
-       NFIT_DEV_DIMM = NVDIMM_FAMILY_INTEL,
-       NFIT_DEV_DIMM_N_HPE1 = NVDIMM_FAMILY_HPE1,
-       NFIT_DEV_DIMM_N_HPE2 = NVDIMM_FAMILY_HPE2,
-       NFIT_SPA_VOLATILE,
-       NFIT_SPA_PM,
-       NFIT_SPA_DCR,
-       NFIT_SPA_BDW,
-       NFIT_SPA_VDISK,
-       NFIT_SPA_VCD,
-       NFIT_SPA_PDISK,
-       NFIT_SPA_PCD,
-       NFIT_DEV_BUS,
-       NFIT_UUID_MAX,
-};
-
-/*
- * Region format interface codes are stored with the interface as the
- * LSB and the function as the MSB.
- */
-#define NFIT_FIC_BYTE cpu_to_le16(0x101) /* byte-addressable energy backed */
-#define NFIT_FIC_BLK cpu_to_le16(0x201) /* block-addressable non-energy backed */
-#define NFIT_FIC_BYTEN cpu_to_le16(0x301) /* byte-addressable non-energy backed */
-
-enum {
-       NFIT_BLK_READ_FLUSH = 1,
-       NFIT_BLK_DCR_LATCH = 2,
-       NFIT_ARS_STATUS_DONE = 0,
-       NFIT_ARS_STATUS_BUSY = 1 << 16,
-       NFIT_ARS_STATUS_NONE = 2 << 16,
-       NFIT_ARS_STATUS_INTR = 3 << 16,
-       NFIT_ARS_START_BUSY = 6,
-       NFIT_ARS_CAP_NONE = 1,
-       NFIT_ARS_F_OVERFLOW = 1,
-       NFIT_ARS_TIMEOUT = 90,
-};
-
-struct nfit_spa {
-       struct acpi_nfit_system_address *spa;
-       struct list_head list;
-       struct nd_region *nd_region;
-       unsigned int ars_done:1;
-       u32 clear_err_unit;
-       u32 max_ars;
-};
-
-struct nfit_dcr {
-       struct acpi_nfit_control_region *dcr;
-       struct list_head list;
-};
-
-struct nfit_bdw {
-       struct acpi_nfit_data_region *bdw;
-       struct list_head list;
-};
-
-struct nfit_idt {
-       struct acpi_nfit_interleave *idt;
-       struct list_head list;
-};
-
-struct nfit_flush {
-       struct acpi_nfit_flush_address *flush;
-       struct list_head list;
-};
-
-struct nfit_memdev {
-       struct acpi_nfit_memory_map *memdev;
-       struct list_head list;
-};
-
-/* assembled tables for a given dimm/memory-device */
-struct nfit_mem {
-       struct nvdimm *nvdimm;
-       struct acpi_nfit_memory_map *memdev_dcr;
-       struct acpi_nfit_memory_map *memdev_pmem;
-       struct acpi_nfit_memory_map *memdev_bdw;
-       struct acpi_nfit_control_region *dcr;
-       struct acpi_nfit_data_region *bdw;
-       struct acpi_nfit_system_address *spa_dcr;
-       struct acpi_nfit_system_address *spa_bdw;
-       struct acpi_nfit_interleave *idt_dcr;
-       struct acpi_nfit_interleave *idt_bdw;
-       struct nfit_flush *nfit_flush;
-       struct list_head list;
-       struct acpi_device *adev;
-       struct acpi_nfit_desc *acpi_desc;
-       unsigned long dsm_mask;
-       int family;
-};
-
-struct acpi_nfit_desc {
-       struct nvdimm_bus_descriptor nd_desc;
-       struct acpi_table_header acpi_header;
-       struct acpi_nfit_header *nfit;
-       struct mutex spa_map_mutex;
-       struct mutex init_mutex;
-       struct list_head spa_maps;
-       struct list_head memdevs;
-       struct list_head flushes;
-       struct list_head dimms;
-       struct list_head spas;
-       struct list_head dcrs;
-       struct list_head bdws;
-       struct list_head idts;
-       struct nvdimm_bus *nvdimm_bus;
-       struct device *dev;
-       struct nd_cmd_ars_status *ars_status;
-       size_t ars_status_size;
-       struct work_struct work;
-       unsigned int cancel:1;
-       unsigned long dimm_cmd_force_en;
-       unsigned long bus_cmd_force_en;
-       int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa,
-                       void *iobuf, u64 len, int rw);
-};
-
-enum nd_blk_mmio_selector {
-       BDW,
-       DCR,
-};
-
-struct nd_blk_addr {
-       union {
-               void __iomem *base;
-               void __pmem  *aperture;
-       };
-};
-
-struct nfit_blk {
-       struct nfit_blk_mmio {
-               struct nd_blk_addr addr;
-               u64 size;
-               u64 base_offset;
-               u32 line_size;
-               u32 num_lines;
-               u32 table_size;
-               struct acpi_nfit_interleave *idt;
-               struct acpi_nfit_system_address *spa;
-       } mmio[2];
-       struct nd_region *nd_region;
-       u64 bdw_offset; /* post interleave offset */
-       u64 stat_offset;
-       u64 cmd_offset;
-       void __iomem *nvdimm_flush;
-       u32 dimm_flags;
-};
-
-enum spa_map_type {
-       SPA_MAP_CONTROL,
-       SPA_MAP_APERTURE,
-};
-
-struct nfit_spa_mapping {
-       struct acpi_nfit_desc *acpi_desc;
-       struct acpi_nfit_system_address *spa;
-       struct list_head list;
-       struct kref kref;
-       enum spa_map_type type;
-       struct nd_blk_addr addr;
-};
-
-static inline struct nfit_spa_mapping *to_spa_map(struct kref *kref)
-{
-       return container_of(kref, struct nfit_spa_mapping, kref);
-}
-
-static inline struct acpi_nfit_memory_map *__to_nfit_memdev(
-               struct nfit_mem *nfit_mem)
-{
-       if (nfit_mem->memdev_dcr)
-               return nfit_mem->memdev_dcr;
-       return nfit_mem->memdev_pmem;
-}
-
-static inline struct acpi_nfit_desc *to_acpi_desc(
-               struct nvdimm_bus_descriptor *nd_desc)
-{
-       return container_of(nd_desc, struct acpi_nfit_desc, nd_desc);
-}
-
-const u8 *to_nfit_uuid(enum nfit_uuids id);
-int acpi_nfit_init(struct acpi_nfit_desc *nfit, acpi_size sz);
-void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev);
-#endif /* __NFIT_H__ */
diff --git a/drivers/acpi/nfit/Kconfig b/drivers/acpi/nfit/Kconfig
new file mode 100644 (file)
index 0000000..dd0d53c
--- /dev/null
@@ -0,0 +1,26 @@
+config ACPI_NFIT
+       tristate "ACPI NVDIMM Firmware Interface Table (NFIT)"
+       depends on PHYS_ADDR_T_64BIT
+       depends on BLK_DEV
+       depends on ARCH_HAS_MMIO_FLUSH
+       select LIBNVDIMM
+       help
+         Infrastructure to probe ACPI 6 compliant platforms for
+         NVDIMMs (NFIT) and register a libnvdimm device tree.  In
+         addition to storage devices this also enables libnvdimm to pass
+         ACPI._DSM messages for platform/dimm configuration.
+
+         To compile this driver as a module, choose M here:
+         the module will be called nfit.
+
+config ACPI_NFIT_DEBUG
+       bool "NFIT DSM debug"
+       depends on ACPI_NFIT
+       depends on DYNAMIC_DEBUG
+       default n
+       help
+         Enabling this option causes the nfit driver to dump the
+         input and output buffers of _DSM operations on the ACPI0012
+         device and its children.  This can be very verbose, so leave
+         it disabled unless you are debugging a hardware / firmware
+         issue.
diff --git a/drivers/acpi/nfit/Makefile b/drivers/acpi/nfit/Makefile
new file mode 100644 (file)
index 0000000..a407e76
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_ACPI_NFIT) := nfit.o
+nfit-y := core.o
+nfit-$(CONFIG_X86_MCE) += mce.o
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
new file mode 100644 (file)
index 0000000..8c234dd
--- /dev/null
@@ -0,0 +1,2784 @@
+/*
+ * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+#include <linux/list_sort.h>
+#include <linux/libnvdimm.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/ndctl.h>
+#include <linux/sysfs.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/acpi.h>
+#include <linux/sort.h>
+#include <linux/pmem.h>
+#include <linux/io.h>
+#include <linux/nd.h>
+#include <asm/cacheflush.h>
+#include "nfit.h"
+
+/*
+ * For readq() and writeq() on 32-bit builds, the hi-lo, lo-hi order is
+ * irrelevant.
+ */
+#include <linux/io-64-nonatomic-hi-lo.h>
+
+static bool force_enable_dimms;
+module_param(force_enable_dimms, bool, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(force_enable_dimms, "Ignore _STA (ACPI DIMM device) status");
+
+static unsigned int scrub_timeout = NFIT_ARS_TIMEOUT;
+module_param(scrub_timeout, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(scrub_timeout, "Initial scrub timeout in seconds");
+
+/* after three payloads of overflow, it's dead jim */
+static unsigned int scrub_overflow_abort = 3;
+module_param(scrub_overflow_abort, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(scrub_overflow_abort,
+               "Number of times we overflow ARS results before abort");
+
+static bool disable_vendor_specific;
+module_param(disable_vendor_specific, bool, S_IRUGO);
+MODULE_PARM_DESC(disable_vendor_specific,
+               "Limit commands to the publicly specified set\n");
+
+LIST_HEAD(acpi_descs);
+DEFINE_MUTEX(acpi_desc_lock);
+
+static struct workqueue_struct *nfit_wq;
+
+struct nfit_table_prev {
+       struct list_head spas;
+       struct list_head memdevs;
+       struct list_head dcrs;
+       struct list_head bdws;
+       struct list_head idts;
+       struct list_head flushes;
+};
+
+static u8 nfit_uuid[NFIT_UUID_MAX][16];
+
+const u8 *to_nfit_uuid(enum nfit_uuids id)
+{
+       return nfit_uuid[id];
+}
+EXPORT_SYMBOL(to_nfit_uuid);
+
+static struct acpi_nfit_desc *to_acpi_nfit_desc(
+               struct nvdimm_bus_descriptor *nd_desc)
+{
+       return container_of(nd_desc, struct acpi_nfit_desc, nd_desc);
+}
+
+static struct acpi_device *to_acpi_dev(struct acpi_nfit_desc *acpi_desc)
+{
+       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
+
+       /*
+        * If provider == 'ACPI.NFIT' we can assume 'dev' is a struct
+        * acpi_device.
+        */
+       if (!nd_desc->provider_name
+                       || strcmp(nd_desc->provider_name, "ACPI.NFIT") != 0)
+               return NULL;
+
+       return to_acpi_device(acpi_desc->dev);
+}
+
+static int xlat_status(void *buf, unsigned int cmd)
+{
+       struct nd_cmd_clear_error *clear_err;
+       struct nd_cmd_ars_status *ars_status;
+       struct nd_cmd_ars_start *ars_start;
+       struct nd_cmd_ars_cap *ars_cap;
+       u16 flags;
+
+       switch (cmd) {
+       case ND_CMD_ARS_CAP:
+               ars_cap = buf;
+               if ((ars_cap->status & 0xffff) == NFIT_ARS_CAP_NONE)
+                       return -ENOTTY;
+
+               /* Command failed */
+               if (ars_cap->status & 0xffff)
+                       return -EIO;
+
+               /* No supported scan types for this range */
+               flags = ND_ARS_PERSISTENT | ND_ARS_VOLATILE;
+               if ((ars_cap->status >> 16 & flags) == 0)
+                       return -ENOTTY;
+               break;
+       case ND_CMD_ARS_START:
+               ars_start = buf;
+               /* ARS is in progress */
+               if ((ars_start->status & 0xffff) == NFIT_ARS_START_BUSY)
+                       return -EBUSY;
+
+               /* Command failed */
+               if (ars_start->status & 0xffff)
+                       return -EIO;
+               break;
+       case ND_CMD_ARS_STATUS:
+               ars_status = buf;
+               /* Command failed */
+               if (ars_status->status & 0xffff)
+                       return -EIO;
+               /* Check extended status (Upper two bytes) */
+               if (ars_status->status == NFIT_ARS_STATUS_DONE)
+                       return 0;
+
+               /* ARS is in progress */
+               if (ars_status->status == NFIT_ARS_STATUS_BUSY)
+                       return -EBUSY;
+
+               /* No ARS performed for the current boot */
+               if (ars_status->status == NFIT_ARS_STATUS_NONE)
+                       return -EAGAIN;
+
+               /*
+                * ARS interrupted, either we overflowed or some other
+                * agent wants the scan to stop.  If we didn't overflow
+                * then just continue with the returned results.
+                */
+               if (ars_status->status == NFIT_ARS_STATUS_INTR) {
+                       if (ars_status->flags & NFIT_ARS_F_OVERFLOW)
+                               return -ENOSPC;
+                       return 0;
+               }
+
+               /* Unknown status */
+               if (ars_status->status >> 16)
+                       return -EIO;
+               break;
+       case ND_CMD_CLEAR_ERROR:
+               clear_err = buf;
+               if (clear_err->status & 0xffff)
+                       return -EIO;
+               if (!clear_err->cleared)
+                       return -EIO;
+               if (clear_err->length > clear_err->cleared)
+                       return clear_err->cleared;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
+               struct nvdimm *nvdimm, unsigned int cmd, void *buf,
+               unsigned int buf_len, int *cmd_rc)
+{
+       struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
+       union acpi_object in_obj, in_buf, *out_obj;
+       const struct nd_cmd_desc *desc = NULL;
+       struct device *dev = acpi_desc->dev;
+       struct nd_cmd_pkg *call_pkg = NULL;
+       const char *cmd_name, *dimm_name;
+       unsigned long cmd_mask, dsm_mask;
+       acpi_handle handle;
+       unsigned int func;
+       const u8 *uuid;
+       u32 offset;
+       int rc, i;
+
+       func = cmd;
+       if (cmd == ND_CMD_CALL) {
+               call_pkg = buf;
+               func = call_pkg->nd_command;
+       }
+
+       if (nvdimm) {
+               struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
+               struct acpi_device *adev = nfit_mem->adev;
+
+               if (!adev)
+                       return -ENOTTY;
+               if (call_pkg && nfit_mem->family != call_pkg->nd_family)
+                       return -ENOTTY;
+
+               dimm_name = nvdimm_name(nvdimm);
+               cmd_name = nvdimm_cmd_name(cmd);
+               cmd_mask = nvdimm_cmd_mask(nvdimm);
+               dsm_mask = nfit_mem->dsm_mask;
+               desc = nd_cmd_dimm_desc(cmd);
+               uuid = to_nfit_uuid(nfit_mem->family);
+               handle = adev->handle;
+       } else {
+               struct acpi_device *adev = to_acpi_dev(acpi_desc);
+
+               cmd_name = nvdimm_bus_cmd_name(cmd);
+               cmd_mask = nd_desc->cmd_mask;
+               dsm_mask = cmd_mask;
+               desc = nd_cmd_bus_desc(cmd);
+               uuid = to_nfit_uuid(NFIT_DEV_BUS);
+               handle = adev->handle;
+               dimm_name = "bus";
+       }
+
+       if (!desc || (cmd && (desc->out_num + desc->in_num == 0)))
+               return -ENOTTY;
+
+       if (!test_bit(cmd, &cmd_mask) || !test_bit(func, &dsm_mask))
+               return -ENOTTY;
+
+       in_obj.type = ACPI_TYPE_PACKAGE;
+       in_obj.package.count = 1;
+       in_obj.package.elements = &in_buf;
+       in_buf.type = ACPI_TYPE_BUFFER;
+       in_buf.buffer.pointer = buf;
+       in_buf.buffer.length = 0;
+
+       /* libnvdimm has already validated the input envelope */
+       for (i = 0; i < desc->in_num; i++)
+               in_buf.buffer.length += nd_cmd_in_size(nvdimm, cmd, desc,
+                               i, buf);
+
+       if (call_pkg) {
+               /* skip over package wrapper */
+               in_buf.buffer.pointer = (void *) &call_pkg->nd_payload;
+               in_buf.buffer.length = call_pkg->nd_size_in;
+       }
+
+       if (IS_ENABLED(CONFIG_ACPI_NFIT_DEBUG)) {
+               dev_dbg(dev, "%s:%s cmd: %d: func: %d input length: %d\n",
+                               __func__, dimm_name, cmd, func,
+                               in_buf.buffer.length);
+               print_hex_dump_debug("nvdimm in  ", DUMP_PREFIX_OFFSET, 4, 4,
+                       in_buf.buffer.pointer,
+                       min_t(u32, 256, in_buf.buffer.length), true);
+       }
+
+       out_obj = acpi_evaluate_dsm(handle, uuid, 1, func, &in_obj);
+       if (!out_obj) {
+               dev_dbg(dev, "%s:%s _DSM failed cmd: %s\n", __func__, dimm_name,
+                               cmd_name);
+               return -EINVAL;
+       }
+
+       if (call_pkg) {
+               call_pkg->nd_fw_size = out_obj->buffer.length;
+               memcpy(call_pkg->nd_payload + call_pkg->nd_size_in,
+                       out_obj->buffer.pointer,
+                       min(call_pkg->nd_fw_size, call_pkg->nd_size_out));
+
+               ACPI_FREE(out_obj);
+               /*
+                * Need to support FW function w/o known size in advance.
+                * Caller can determine required size based upon nd_fw_size.
+                * If we return an error (like elsewhere) then caller wouldn't
+                * be able to rely upon data returned to make calculation.
+                */
+               return 0;
+       }
+
+       if (out_obj->package.type != ACPI_TYPE_BUFFER) {
+               dev_dbg(dev, "%s:%s unexpected output object type cmd: %s type: %d\n",
+                               __func__, dimm_name, cmd_name, out_obj->type);
+               rc = -EINVAL;
+               goto out;
+       }
+
+       if (IS_ENABLED(CONFIG_ACPI_NFIT_DEBUG)) {
+               dev_dbg(dev, "%s:%s cmd: %s output length: %d\n", __func__,
+                               dimm_name, cmd_name, out_obj->buffer.length);
+               print_hex_dump_debug(cmd_name, DUMP_PREFIX_OFFSET, 4,
+                               4, out_obj->buffer.pointer, min_t(u32, 128,
+                                       out_obj->buffer.length), true);
+       }
+
+       for (i = 0, offset = 0; i < desc->out_num; i++) {
+               u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i, buf,
+                               (u32 *) out_obj->buffer.pointer);
+
+               if (offset + out_size > out_obj->buffer.length) {
+                       dev_dbg(dev, "%s:%s output object underflow cmd: %s field: %d\n",
+                                       __func__, dimm_name, cmd_name, i);
+                       break;
+               }
+
+               if (in_buf.buffer.length + offset + out_size > buf_len) {
+                       dev_dbg(dev, "%s:%s output overrun cmd: %s field: %d\n",
+                                       __func__, dimm_name, cmd_name, i);
+                       rc = -ENXIO;
+                       goto out;
+               }
+               memcpy(buf + in_buf.buffer.length + offset,
+                               out_obj->buffer.pointer + offset, out_size);
+               offset += out_size;
+       }
+       if (offset + in_buf.buffer.length < buf_len) {
+               if (i >= 1) {
+                       /*
+                        * status valid, return the number of bytes left
+                        * unfilled in the output buffer
+                        */
+                       rc = buf_len - offset - in_buf.buffer.length;
+                       if (cmd_rc)
+                               *cmd_rc = xlat_status(buf, cmd);
+               } else {
+                       dev_err(dev, "%s:%s underrun cmd: %s buf_len: %d out_len: %d\n",
+                                       __func__, dimm_name, cmd_name, buf_len,
+                                       offset);
+                       rc = -ENXIO;
+               }
+       } else {
+               rc = 0;
+               if (cmd_rc)
+                       *cmd_rc = xlat_status(buf, cmd);
+       }
+
+ out:
+       ACPI_FREE(out_obj);
+
+       return rc;
+}
+
+static const char *spa_type_name(u16 type)
+{
+       static const char *to_name[] = {
+               [NFIT_SPA_VOLATILE] = "volatile",
+               [NFIT_SPA_PM] = "pmem",
+               [NFIT_SPA_DCR] = "dimm-control-region",
+               [NFIT_SPA_BDW] = "block-data-window",
+               [NFIT_SPA_VDISK] = "volatile-disk",
+               [NFIT_SPA_VCD] = "volatile-cd",
+               [NFIT_SPA_PDISK] = "persistent-disk",
+               [NFIT_SPA_PCD] = "persistent-cd",
+
+       };
+
+       if (type > NFIT_SPA_PCD)
+               return "unknown";
+
+       return to_name[type];
+}
+
+int nfit_spa_type(struct acpi_nfit_system_address *spa)
+{
+       int i;
+
+       for (i = 0; i < NFIT_UUID_MAX; i++)
+               if (memcmp(to_nfit_uuid(i), spa->range_guid, 16) == 0)
+                       return i;
+       return -1;
+}
+
+static bool add_spa(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_table_prev *prev,
+               struct acpi_nfit_system_address *spa)
+{
+       struct device *dev = acpi_desc->dev;
+       struct nfit_spa *nfit_spa;
+
+       if (spa->header.length != sizeof(*spa))
+               return false;
+
+       list_for_each_entry(nfit_spa, &prev->spas, list) {
+               if (memcmp(nfit_spa->spa, spa, sizeof(*spa)) == 0) {
+                       list_move_tail(&nfit_spa->list, &acpi_desc->spas);
+                       return true;
+               }
+       }
+
+       nfit_spa = devm_kzalloc(dev, sizeof(*nfit_spa) + sizeof(*spa),
+                       GFP_KERNEL);
+       if (!nfit_spa)
+               return false;
+       INIT_LIST_HEAD(&nfit_spa->list);
+       memcpy(nfit_spa->spa, spa, sizeof(*spa));
+       list_add_tail(&nfit_spa->list, &acpi_desc->spas);
+       dev_dbg(dev, "%s: spa index: %d type: %s\n", __func__,
+                       spa->range_index,
+                       spa_type_name(nfit_spa_type(spa)));
+       return true;
+}
+
+static bool add_memdev(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_table_prev *prev,
+               struct acpi_nfit_memory_map *memdev)
+{
+       struct device *dev = acpi_desc->dev;
+       struct nfit_memdev *nfit_memdev;
+
+       if (memdev->header.length != sizeof(*memdev))
+               return false;
+
+       list_for_each_entry(nfit_memdev, &prev->memdevs, list)
+               if (memcmp(nfit_memdev->memdev, memdev, sizeof(*memdev)) == 0) {
+                       list_move_tail(&nfit_memdev->list, &acpi_desc->memdevs);
+                       return true;
+               }
+
+       nfit_memdev = devm_kzalloc(dev, sizeof(*nfit_memdev) + sizeof(*memdev),
+                       GFP_KERNEL);
+       if (!nfit_memdev)
+               return false;
+       INIT_LIST_HEAD(&nfit_memdev->list);
+       memcpy(nfit_memdev->memdev, memdev, sizeof(*memdev));
+       list_add_tail(&nfit_memdev->list, &acpi_desc->memdevs);
+       dev_dbg(dev, "%s: memdev handle: %#x spa: %d dcr: %d\n",
+                       __func__, memdev->device_handle, memdev->range_index,
+                       memdev->region_index);
+       return true;
+}
+
+/*
+ * An implementation may provide a truncated control region if no block windows
+ * are defined.
+ */
+static size_t sizeof_dcr(struct acpi_nfit_control_region *dcr)
+{
+       if (dcr->header.length < offsetof(struct acpi_nfit_control_region,
+                               window_size))
+               return 0;
+       if (dcr->windows)
+               return sizeof(*dcr);
+       return offsetof(struct acpi_nfit_control_region, window_size);
+}
+
+static bool add_dcr(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_table_prev *prev,
+               struct acpi_nfit_control_region *dcr)
+{
+       struct device *dev = acpi_desc->dev;
+       struct nfit_dcr *nfit_dcr;
+
+       if (!sizeof_dcr(dcr))
+               return false;
+
+       list_for_each_entry(nfit_dcr, &prev->dcrs, list)
+               if (memcmp(nfit_dcr->dcr, dcr, sizeof_dcr(dcr)) == 0) {
+                       list_move_tail(&nfit_dcr->list, &acpi_desc->dcrs);
+                       return true;
+               }
+
+       nfit_dcr = devm_kzalloc(dev, sizeof(*nfit_dcr) + sizeof(*dcr),
+                       GFP_KERNEL);
+       if (!nfit_dcr)
+               return false;
+       INIT_LIST_HEAD(&nfit_dcr->list);
+       memcpy(nfit_dcr->dcr, dcr, sizeof_dcr(dcr));
+       list_add_tail(&nfit_dcr->list, &acpi_desc->dcrs);
+       dev_dbg(dev, "%s: dcr index: %d windows: %d\n", __func__,
+                       dcr->region_index, dcr->windows);
+       return true;
+}
+
+static bool add_bdw(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_table_prev *prev,
+               struct acpi_nfit_data_region *bdw)
+{
+       struct device *dev = acpi_desc->dev;
+       struct nfit_bdw *nfit_bdw;
+
+       if (bdw->header.length != sizeof(*bdw))
+               return false;
+       list_for_each_entry(nfit_bdw, &prev->bdws, list)
+               if (memcmp(nfit_bdw->bdw, bdw, sizeof(*bdw)) == 0) {
+                       list_move_tail(&nfit_bdw->list, &acpi_desc->bdws);
+                       return true;
+               }
+
+       nfit_bdw = devm_kzalloc(dev, sizeof(*nfit_bdw) + sizeof(*bdw),
+                       GFP_KERNEL);
+       if (!nfit_bdw)
+               return false;
+       INIT_LIST_HEAD(&nfit_bdw->list);
+       memcpy(nfit_bdw->bdw, bdw, sizeof(*bdw));
+       list_add_tail(&nfit_bdw->list, &acpi_desc->bdws);
+       dev_dbg(dev, "%s: bdw dcr: %d windows: %d\n", __func__,
+                       bdw->region_index, bdw->windows);
+       return true;
+}
+
+static size_t sizeof_idt(struct acpi_nfit_interleave *idt)
+{
+       if (idt->header.length < sizeof(*idt))
+               return 0;
+       return sizeof(*idt) + sizeof(u32) * (idt->line_count - 1);
+}
+
+static bool add_idt(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_table_prev *prev,
+               struct acpi_nfit_interleave *idt)
+{
+       struct device *dev = acpi_desc->dev;
+       struct nfit_idt *nfit_idt;
+
+       if (!sizeof_idt(idt))
+               return false;
+
+       list_for_each_entry(nfit_idt, &prev->idts, list) {
+               if (sizeof_idt(nfit_idt->idt) != sizeof_idt(idt))
+                       continue;
+
+               if (memcmp(nfit_idt->idt, idt, sizeof_idt(idt)) == 0) {
+                       list_move_tail(&nfit_idt->list, &acpi_desc->idts);
+                       return true;
+               }
+       }
+
+       nfit_idt = devm_kzalloc(dev, sizeof(*nfit_idt) + sizeof_idt(idt),
+                       GFP_KERNEL);
+       if (!nfit_idt)
+               return false;
+       INIT_LIST_HEAD(&nfit_idt->list);
+       memcpy(nfit_idt->idt, idt, sizeof_idt(idt));
+       list_add_tail(&nfit_idt->list, &acpi_desc->idts);
+       dev_dbg(dev, "%s: idt index: %d num_lines: %d\n", __func__,
+                       idt->interleave_index, idt->line_count);
+       return true;
+}
+
+static size_t sizeof_flush(struct acpi_nfit_flush_address *flush)
+{
+       if (flush->header.length < sizeof(*flush))
+               return 0;
+       return sizeof(*flush) + sizeof(u64) * (flush->hint_count - 1);
+}
+
+static bool add_flush(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_table_prev *prev,
+               struct acpi_nfit_flush_address *flush)
+{
+       struct device *dev = acpi_desc->dev;
+       struct nfit_flush *nfit_flush;
+
+       if (!sizeof_flush(flush))
+               return false;
+
+       list_for_each_entry(nfit_flush, &prev->flushes, list) {
+               if (sizeof_flush(nfit_flush->flush) != sizeof_flush(flush))
+                       continue;
+
+               if (memcmp(nfit_flush->flush, flush,
+                                       sizeof_flush(flush)) == 0) {
+                       list_move_tail(&nfit_flush->list, &acpi_desc->flushes);
+                       return true;
+               }
+       }
+
+       nfit_flush = devm_kzalloc(dev, sizeof(*nfit_flush)
+                       + sizeof_flush(flush), GFP_KERNEL);
+       if (!nfit_flush)
+               return false;
+       INIT_LIST_HEAD(&nfit_flush->list);
+       memcpy(nfit_flush->flush, flush, sizeof_flush(flush));
+       list_add_tail(&nfit_flush->list, &acpi_desc->flushes);
+       dev_dbg(dev, "%s: nfit_flush handle: %d hint_count: %d\n", __func__,
+                       flush->device_handle, flush->hint_count);
+       return true;
+}
+
+static void *add_table(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_table_prev *prev, void *table, const void *end)
+{
+       struct device *dev = acpi_desc->dev;
+       struct acpi_nfit_header *hdr;
+       void *err = ERR_PTR(-ENOMEM);
+
+       if (table >= end)
+               return NULL;
+
+       hdr = table;
+       if (!hdr->length) {
+               dev_warn(dev, "found a zero length table '%d' parsing nfit\n",
+                       hdr->type);
+               return NULL;
+       }
+
+       switch (hdr->type) {
+       case ACPI_NFIT_TYPE_SYSTEM_ADDRESS:
+               if (!add_spa(acpi_desc, prev, table))
+                       return err;
+               break;
+       case ACPI_NFIT_TYPE_MEMORY_MAP:
+               if (!add_memdev(acpi_desc, prev, table))
+                       return err;
+               break;
+       case ACPI_NFIT_TYPE_CONTROL_REGION:
+               if (!add_dcr(acpi_desc, prev, table))
+                       return err;
+               break;
+       case ACPI_NFIT_TYPE_DATA_REGION:
+               if (!add_bdw(acpi_desc, prev, table))
+                       return err;
+               break;
+       case ACPI_NFIT_TYPE_INTERLEAVE:
+               if (!add_idt(acpi_desc, prev, table))
+                       return err;
+               break;
+       case ACPI_NFIT_TYPE_FLUSH_ADDRESS:
+               if (!add_flush(acpi_desc, prev, table))
+                       return err;
+               break;
+       case ACPI_NFIT_TYPE_SMBIOS:
+               dev_dbg(dev, "%s: smbios\n", __func__);
+               break;
+       default:
+               dev_err(dev, "unknown table '%d' parsing nfit\n", hdr->type);
+               break;
+       }
+
+       return table + hdr->length;
+}
+
+static void nfit_mem_find_spa_bdw(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_mem *nfit_mem)
+{
+       u32 device_handle = __to_nfit_memdev(nfit_mem)->device_handle;
+       u16 dcr = nfit_mem->dcr->region_index;
+       struct nfit_spa *nfit_spa;
+
+       list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
+               u16 range_index = nfit_spa->spa->range_index;
+               int type = nfit_spa_type(nfit_spa->spa);
+               struct nfit_memdev *nfit_memdev;
+
+               if (type != NFIT_SPA_BDW)
+                       continue;
+
+               list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
+                       if (nfit_memdev->memdev->range_index != range_index)
+                               continue;
+                       if (nfit_memdev->memdev->device_handle != device_handle)
+                               continue;
+                       if (nfit_memdev->memdev->region_index != dcr)
+                               continue;
+
+                       nfit_mem->spa_bdw = nfit_spa->spa;
+                       return;
+               }
+       }
+
+       dev_dbg(acpi_desc->dev, "SPA-BDW not found for SPA-DCR %d\n",
+                       nfit_mem->spa_dcr->range_index);
+       nfit_mem->bdw = NULL;
+}
+
+static void nfit_mem_init_bdw(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_mem *nfit_mem, struct acpi_nfit_system_address *spa)
+{
+       u16 dcr = __to_nfit_memdev(nfit_mem)->region_index;
+       struct nfit_memdev *nfit_memdev;
+       struct nfit_bdw *nfit_bdw;
+       struct nfit_idt *nfit_idt;
+       u16 idt_idx, range_index;
+
+       list_for_each_entry(nfit_bdw, &acpi_desc->bdws, list) {
+               if (nfit_bdw->bdw->region_index != dcr)
+                       continue;
+               nfit_mem->bdw = nfit_bdw->bdw;
+               break;
+       }
+
+       if (!nfit_mem->bdw)
+               return;
+
+       nfit_mem_find_spa_bdw(acpi_desc, nfit_mem);
+
+       if (!nfit_mem->spa_bdw)
+               return;
+
+       range_index = nfit_mem->spa_bdw->range_index;
+       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
+               if (nfit_memdev->memdev->range_index != range_index ||
+                               nfit_memdev->memdev->region_index != dcr)
+                       continue;
+               nfit_mem->memdev_bdw = nfit_memdev->memdev;
+               idt_idx = nfit_memdev->memdev->interleave_index;
+               list_for_each_entry(nfit_idt, &acpi_desc->idts, list) {
+                       if (nfit_idt->idt->interleave_index != idt_idx)
+                               continue;
+                       nfit_mem->idt_bdw = nfit_idt->idt;
+                       break;
+               }
+               break;
+       }
+}
+
+static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
+               struct acpi_nfit_system_address *spa)
+{
+       struct nfit_mem *nfit_mem, *found;
+       struct nfit_memdev *nfit_memdev;
+       int type = nfit_spa_type(spa);
+
+       switch (type) {
+       case NFIT_SPA_DCR:
+       case NFIT_SPA_PM:
+               break;
+       default:
+               return 0;
+       }
+
+       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
+               struct nfit_flush *nfit_flush;
+               struct nfit_dcr *nfit_dcr;
+               u32 device_handle;
+               u16 dcr;
+
+               if (nfit_memdev->memdev->range_index != spa->range_index)
+                       continue;
+               found = NULL;
+               dcr = nfit_memdev->memdev->region_index;
+               device_handle = nfit_memdev->memdev->device_handle;
+               list_for_each_entry(nfit_mem, &acpi_desc->dimms, list)
+                       if (__to_nfit_memdev(nfit_mem)->device_handle
+                                       == device_handle) {
+                               found = nfit_mem;
+                               break;
+                       }
+
+               if (found)
+                       nfit_mem = found;
+               else {
+                       nfit_mem = devm_kzalloc(acpi_desc->dev,
+                                       sizeof(*nfit_mem), GFP_KERNEL);
+                       if (!nfit_mem)
+                               return -ENOMEM;
+                       INIT_LIST_HEAD(&nfit_mem->list);
+                       nfit_mem->acpi_desc = acpi_desc;
+                       list_add(&nfit_mem->list, &acpi_desc->dimms);
+               }
+
+               list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) {
+                       if (nfit_dcr->dcr->region_index != dcr)
+                               continue;
+                       /*
+                        * Record the control region for the dimm.  For
+                        * the ACPI 6.1 case, where there are separate
+                        * control regions for the pmem vs blk
+                        * interfaces, be sure to record the extended
+                        * blk details.
+                        */
+                       if (!nfit_mem->dcr)
+                               nfit_mem->dcr = nfit_dcr->dcr;
+                       else if (nfit_mem->dcr->windows == 0
+                                       && nfit_dcr->dcr->windows)
+                               nfit_mem->dcr = nfit_dcr->dcr;
+                       break;
+               }
+
+               list_for_each_entry(nfit_flush, &acpi_desc->flushes, list) {
+                       struct acpi_nfit_flush_address *flush;
+                       u16 i;
+
+                       if (nfit_flush->flush->device_handle != device_handle)
+                               continue;
+                       nfit_mem->nfit_flush = nfit_flush;
+                       flush = nfit_flush->flush;
+                       nfit_mem->flush_wpq = devm_kzalloc(acpi_desc->dev,
+                                       flush->hint_count
+                                       * sizeof(struct resource), GFP_KERNEL);
+                       if (!nfit_mem->flush_wpq)
+                               return -ENOMEM;
+                       for (i = 0; i < flush->hint_count; i++) {
+                               struct resource *res = &nfit_mem->flush_wpq[i];
+
+                               res->start = flush->hint_address[i];
+                               res->end = res->start + 8 - 1;
+                       }
+                       break;
+               }
+
+               if (dcr && !nfit_mem->dcr) {
+                       dev_err(acpi_desc->dev, "SPA %d missing DCR %d\n",
+                                       spa->range_index, dcr);
+                       return -ENODEV;
+               }
+
+               if (type == NFIT_SPA_DCR) {
+                       struct nfit_idt *nfit_idt;
+                       u16 idt_idx;
+
+                       /* multiple dimms may share a SPA when interleaved */
+                       nfit_mem->spa_dcr = spa;
+                       nfit_mem->memdev_dcr = nfit_memdev->memdev;
+                       idt_idx = nfit_memdev->memdev->interleave_index;
+                       list_for_each_entry(nfit_idt, &acpi_desc->idts, list) {
+                               if (nfit_idt->idt->interleave_index != idt_idx)
+                                       continue;
+                               nfit_mem->idt_dcr = nfit_idt->idt;
+                               break;
+                       }
+                       nfit_mem_init_bdw(acpi_desc, nfit_mem, spa);
+               } else {
+                       /*
+                        * A single dimm may belong to multiple SPA-PM
+                        * ranges, record at least one in addition to
+                        * any SPA-DCR range.
+                        */
+                       nfit_mem->memdev_pmem = nfit_memdev->memdev;
+               }
+       }
+
+       return 0;
+}
+
+static int nfit_mem_cmp(void *priv, struct list_head *_a, struct list_head *_b)
+{
+       struct nfit_mem *a = container_of(_a, typeof(*a), list);
+       struct nfit_mem *b = container_of(_b, typeof(*b), list);
+       u32 handleA, handleB;
+
+       handleA = __to_nfit_memdev(a)->device_handle;
+       handleB = __to_nfit_memdev(b)->device_handle;
+       if (handleA < handleB)
+               return -1;
+       else if (handleA > handleB)
+               return 1;
+       return 0;
+}
+
+static int nfit_mem_init(struct acpi_nfit_desc *acpi_desc)
+{
+       struct nfit_spa *nfit_spa;
+
+       /*
+        * For each SPA-DCR or SPA-PMEM address range find its
+        * corresponding MEMDEV(s).  From each MEMDEV find the
+        * corresponding DCR.  Then, if we're operating on a SPA-DCR,
+        * try to find a SPA-BDW and a corresponding BDW that references
+        * the DCR.  Throw it all into an nfit_mem object.  Note, that
+        * BDWs are optional.
+        */
+       list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
+               int rc;
+
+               rc = nfit_mem_dcr_init(acpi_desc, nfit_spa->spa);
+               if (rc)
+                       return rc;
+       }
+
+       list_sort(NULL, &acpi_desc->dimms, nfit_mem_cmp);
+
+       return 0;
+}
+
+static ssize_t revision_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
+       struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
+       struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
+
+       return sprintf(buf, "%d\n", acpi_desc->acpi_header.revision);
+}
+static DEVICE_ATTR_RO(revision);
+
+/*
+ * This shows the number of full Address Range Scrubs that have been
+ * completed since driver load time. Userspace can wait on this using
+ * select/poll etc. A '+' at the end indicates an ARS is in progress
+ */
+static ssize_t scrub_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nvdimm_bus_descriptor *nd_desc;
+       ssize_t rc = -ENXIO;
+
+       device_lock(dev);
+       nd_desc = dev_get_drvdata(dev);
+       if (nd_desc) {
+               struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
+
+               rc = sprintf(buf, "%d%s", acpi_desc->scrub_count,
+                               (work_busy(&acpi_desc->work)) ? "+\n" : "\n");
+       }
+       device_unlock(dev);
+       return rc;
+}
+
+static ssize_t scrub_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t size)
+{
+       struct nvdimm_bus_descriptor *nd_desc;
+       ssize_t rc;
+       long val;
+
+       rc = kstrtol(buf, 0, &val);
+       if (rc)
+               return rc;
+       if (val != 1)
+               return -EINVAL;
+
+       device_lock(dev);
+       nd_desc = dev_get_drvdata(dev);
+       if (nd_desc) {
+               struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
+
+               rc = acpi_nfit_ars_rescan(acpi_desc);
+       }
+       device_unlock(dev);
+       if (rc)
+               return rc;
+       return size;
+}
+static DEVICE_ATTR_RW(scrub);
+
+static bool ars_supported(struct nvdimm_bus *nvdimm_bus)
+{
+       struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
+       const unsigned long mask = 1 << ND_CMD_ARS_CAP | 1 << ND_CMD_ARS_START
+               | 1 << ND_CMD_ARS_STATUS;
+
+       return (nd_desc->cmd_mask & mask) == mask;
+}
+
+static umode_t nfit_visible(struct kobject *kobj, struct attribute *a, int n)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
+
+       if (a == &dev_attr_scrub.attr && !ars_supported(nvdimm_bus))
+               return 0;
+       return a->mode;
+}
+
+static struct attribute *acpi_nfit_attributes[] = {
+       &dev_attr_revision.attr,
+       &dev_attr_scrub.attr,
+       NULL,
+};
+
+static struct attribute_group acpi_nfit_attribute_group = {
+       .name = "nfit",
+       .attrs = acpi_nfit_attributes,
+       .is_visible = nfit_visible,
+};
+
+static const struct attribute_group *acpi_nfit_attribute_groups[] = {
+       &nvdimm_bus_attribute_group,
+       &acpi_nfit_attribute_group,
+       NULL,
+};
+
+static struct acpi_nfit_memory_map *to_nfit_memdev(struct device *dev)
+{
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
+
+       return __to_nfit_memdev(nfit_mem);
+}
+
+static struct acpi_nfit_control_region *to_nfit_dcr(struct device *dev)
+{
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
+
+       return nfit_mem->dcr;
+}
+
+static ssize_t handle_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_memory_map *memdev = to_nfit_memdev(dev);
+
+       return sprintf(buf, "%#x\n", memdev->device_handle);
+}
+static DEVICE_ATTR_RO(handle);
+
+static ssize_t phys_id_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_memory_map *memdev = to_nfit_memdev(dev);
+
+       return sprintf(buf, "%#x\n", memdev->physical_id);
+}
+static DEVICE_ATTR_RO(phys_id);
+
+static ssize_t vendor_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->vendor_id));
+}
+static DEVICE_ATTR_RO(vendor);
+
+static ssize_t rev_id_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->revision_id));
+}
+static DEVICE_ATTR_RO(rev_id);
+
+static ssize_t device_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->device_id));
+}
+static DEVICE_ATTR_RO(device);
+
+static ssize_t subsystem_vendor_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->subsystem_vendor_id));
+}
+static DEVICE_ATTR_RO(subsystem_vendor);
+
+static ssize_t subsystem_rev_id_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       return sprintf(buf, "0x%04x\n",
+                       be16_to_cpu(dcr->subsystem_revision_id));
+}
+static DEVICE_ATTR_RO(subsystem_rev_id);
+
+static ssize_t subsystem_device_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->subsystem_device_id));
+}
+static DEVICE_ATTR_RO(subsystem_device);
+
+static int num_nvdimm_formats(struct nvdimm *nvdimm)
+{
+       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
+       int formats = 0;
+
+       if (nfit_mem->memdev_pmem)
+               formats++;
+       if (nfit_mem->memdev_bdw)
+               formats++;
+       return formats;
+}
+
+static ssize_t format_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       return sprintf(buf, "0x%04x\n", le16_to_cpu(dcr->code));
+}
+static DEVICE_ATTR_RO(format);
+
+static ssize_t format1_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       u32 handle;
+       ssize_t rc = -ENXIO;
+       struct nfit_mem *nfit_mem;
+       struct nfit_memdev *nfit_memdev;
+       struct acpi_nfit_desc *acpi_desc;
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       nfit_mem = nvdimm_provider_data(nvdimm);
+       acpi_desc = nfit_mem->acpi_desc;
+       handle = to_nfit_memdev(dev)->device_handle;
+
+       /* assumes DIMMs have at most 2 published interface codes */
+       mutex_lock(&acpi_desc->init_mutex);
+       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
+               struct acpi_nfit_memory_map *memdev = nfit_memdev->memdev;
+               struct nfit_dcr *nfit_dcr;
+
+               if (memdev->device_handle != handle)
+                       continue;
+
+               list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) {
+                       if (nfit_dcr->dcr->region_index != memdev->region_index)
+                               continue;
+                       if (nfit_dcr->dcr->code == dcr->code)
+                               continue;
+                       rc = sprintf(buf, "0x%04x\n",
+                                       le16_to_cpu(nfit_dcr->dcr->code));
+                       break;
+               }
+               if (rc != ENXIO)
+                       break;
+       }
+       mutex_unlock(&acpi_desc->init_mutex);
+       return rc;
+}
+static DEVICE_ATTR_RO(format1);
+
+static ssize_t formats_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+
+       return sprintf(buf, "%d\n", num_nvdimm_formats(nvdimm));
+}
+static DEVICE_ATTR_RO(formats);
+
+static ssize_t serial_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       return sprintf(buf, "0x%08x\n", be32_to_cpu(dcr->serial_number));
+}
+static DEVICE_ATTR_RO(serial);
+
+static ssize_t family_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
+
+       if (nfit_mem->family < 0)
+               return -ENXIO;
+       return sprintf(buf, "%d\n", nfit_mem->family);
+}
+static DEVICE_ATTR_RO(family);
+
+static ssize_t dsm_mask_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
+
+       if (nfit_mem->family < 0)
+               return -ENXIO;
+       return sprintf(buf, "%#lx\n", nfit_mem->dsm_mask);
+}
+static DEVICE_ATTR_RO(dsm_mask);
+
+static ssize_t flags_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       u16 flags = to_nfit_memdev(dev)->flags;
+
+       return sprintf(buf, "%s%s%s%s%s\n",
+               flags & ACPI_NFIT_MEM_SAVE_FAILED ? "save_fail " : "",
+               flags & ACPI_NFIT_MEM_RESTORE_FAILED ? "restore_fail " : "",
+               flags & ACPI_NFIT_MEM_FLUSH_FAILED ? "flush_fail " : "",
+               flags & ACPI_NFIT_MEM_NOT_ARMED ? "not_armed " : "",
+               flags & ACPI_NFIT_MEM_HEALTH_OBSERVED ? "smart_event " : "");
+}
+static DEVICE_ATTR_RO(flags);
+
+static ssize_t id_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       if (dcr->valid_fields & ACPI_NFIT_CONTROL_MFG_INFO_VALID)
+               return sprintf(buf, "%04x-%02x-%04x-%08x\n",
+                               be16_to_cpu(dcr->vendor_id),
+                               dcr->manufacturing_location,
+                               be16_to_cpu(dcr->manufacturing_date),
+                               be32_to_cpu(dcr->serial_number));
+       else
+               return sprintf(buf, "%04x-%08x\n",
+                               be16_to_cpu(dcr->vendor_id),
+                               be32_to_cpu(dcr->serial_number));
+}
+static DEVICE_ATTR_RO(id);
+
+static struct attribute *acpi_nfit_dimm_attributes[] = {
+       &dev_attr_handle.attr,
+       &dev_attr_phys_id.attr,
+       &dev_attr_vendor.attr,
+       &dev_attr_device.attr,
+       &dev_attr_rev_id.attr,
+       &dev_attr_subsystem_vendor.attr,
+       &dev_attr_subsystem_device.attr,
+       &dev_attr_subsystem_rev_id.attr,
+       &dev_attr_format.attr,
+       &dev_attr_formats.attr,
+       &dev_attr_format1.attr,
+       &dev_attr_serial.attr,
+       &dev_attr_flags.attr,
+       &dev_attr_id.attr,
+       &dev_attr_family.attr,
+       &dev_attr_dsm_mask.attr,
+       NULL,
+};
+
+static umode_t acpi_nfit_dimm_attr_visible(struct kobject *kobj,
+               struct attribute *a, int n)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+
+       if (!to_nfit_dcr(dev))
+               return 0;
+       if (a == &dev_attr_format1.attr && num_nvdimm_formats(nvdimm) <= 1)
+               return 0;
+       return a->mode;
+}
+
+static struct attribute_group acpi_nfit_dimm_attribute_group = {
+       .name = "nfit",
+       .attrs = acpi_nfit_dimm_attributes,
+       .is_visible = acpi_nfit_dimm_attr_visible,
+};
+
+static const struct attribute_group *acpi_nfit_dimm_attribute_groups[] = {
+       &nvdimm_attribute_group,
+       &nd_device_attribute_group,
+       &acpi_nfit_dimm_attribute_group,
+       NULL,
+};
+
+static struct nvdimm *acpi_nfit_dimm_by_handle(struct acpi_nfit_desc *acpi_desc,
+               u32 device_handle)
+{
+       struct nfit_mem *nfit_mem;
+
+       list_for_each_entry(nfit_mem, &acpi_desc->dimms, list)
+               if (__to_nfit_memdev(nfit_mem)->device_handle == device_handle)
+                       return nfit_mem->nvdimm;
+
+       return NULL;
+}
+
+static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_mem *nfit_mem, u32 device_handle)
+{
+       struct acpi_device *adev, *adev_dimm;
+       struct device *dev = acpi_desc->dev;
+       unsigned long dsm_mask;
+       const u8 *uuid;
+       int i;
+
+       /* nfit test assumes 1:1 relationship between commands and dsms */
+       nfit_mem->dsm_mask = acpi_desc->dimm_cmd_force_en;
+       nfit_mem->family = NVDIMM_FAMILY_INTEL;
+       adev = to_acpi_dev(acpi_desc);
+       if (!adev)
+               return 0;
+
+       adev_dimm = acpi_find_child_device(adev, device_handle, false);
+       nfit_mem->adev = adev_dimm;
+       if (!adev_dimm) {
+               dev_err(dev, "no ACPI.NFIT device with _ADR %#x, disabling...\n",
+                               device_handle);
+               return force_enable_dimms ? 0 : -ENODEV;
+       }
+
+       /*
+        * Until standardization materializes we need to consider 4
+        * different command sets.  Note, that checking for function0 (bit0)
+        * tells us if any commands are reachable through this uuid.
+        */
+       for (i = NVDIMM_FAMILY_INTEL; i <= NVDIMM_FAMILY_MSFT; i++)
+               if (acpi_check_dsm(adev_dimm->handle, to_nfit_uuid(i), 1, 1))
+                       break;
+
+       /* limit the supported commands to those that are publicly documented */
+       nfit_mem->family = i;
+       if (nfit_mem->family == NVDIMM_FAMILY_INTEL) {
+               dsm_mask = 0x3fe;
+               if (disable_vendor_specific)
+                       dsm_mask &= ~(1 << ND_CMD_VENDOR);
+       } else if (nfit_mem->family == NVDIMM_FAMILY_HPE1) {
+               dsm_mask = 0x1c3c76;
+       } else if (nfit_mem->family == NVDIMM_FAMILY_HPE2) {
+               dsm_mask = 0x1fe;
+               if (disable_vendor_specific)
+                       dsm_mask &= ~(1 << 8);
+       } else if (nfit_mem->family == NVDIMM_FAMILY_MSFT) {
+               dsm_mask = 0xffffffff;
+       } else {
+               dev_dbg(dev, "unknown dimm command family\n");
+               nfit_mem->family = -1;
+               /* DSMs are optional, continue loading the driver... */
+               return 0;
+       }
+
+       uuid = to_nfit_uuid(nfit_mem->family);
+       for_each_set_bit(i, &dsm_mask, BITS_PER_LONG)
+               if (acpi_check_dsm(adev_dimm->handle, uuid, 1, 1ULL << i))
+                       set_bit(i, &nfit_mem->dsm_mask);
+
+       return 0;
+}
+
+static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
+{
+       struct nfit_mem *nfit_mem;
+       int dimm_count = 0;
+
+       list_for_each_entry(nfit_mem, &acpi_desc->dimms, list) {
+               struct acpi_nfit_flush_address *flush;
+               unsigned long flags = 0, cmd_mask;
+               struct nvdimm *nvdimm;
+               u32 device_handle;
+               u16 mem_flags;
+               int rc;
+
+               device_handle = __to_nfit_memdev(nfit_mem)->device_handle;
+               nvdimm = acpi_nfit_dimm_by_handle(acpi_desc, device_handle);
+               if (nvdimm) {
+                       dimm_count++;
+                       continue;
+               }
+
+               if (nfit_mem->bdw && nfit_mem->memdev_pmem)
+                       flags |= NDD_ALIASING;
+
+               mem_flags = __to_nfit_memdev(nfit_mem)->flags;
+               if (mem_flags & ACPI_NFIT_MEM_NOT_ARMED)
+                       flags |= NDD_UNARMED;
+
+               rc = acpi_nfit_add_dimm(acpi_desc, nfit_mem, device_handle);
+               if (rc)
+                       continue;
+
+               /*
+                * TODO: provide translation for non-NVDIMM_FAMILY_INTEL
+                * devices (i.e. from nd_cmd to acpi_dsm) to standardize the
+                * userspace interface.
+                */
+               cmd_mask = 1UL << ND_CMD_CALL;
+               if (nfit_mem->family == NVDIMM_FAMILY_INTEL)
+                       cmd_mask |= nfit_mem->dsm_mask;
+
+               flush = nfit_mem->nfit_flush ? nfit_mem->nfit_flush->flush
+                       : NULL;
+               nvdimm = nvdimm_create(acpi_desc->nvdimm_bus, nfit_mem,
+                               acpi_nfit_dimm_attribute_groups,
+                               flags, cmd_mask, flush ? flush->hint_count : 0,
+                               nfit_mem->flush_wpq);
+               if (!nvdimm)
+                       return -ENOMEM;
+
+               nfit_mem->nvdimm = nvdimm;
+               dimm_count++;
+
+               if ((mem_flags & ACPI_NFIT_MEM_FAILED_MASK) == 0)
+                       continue;
+
+               dev_info(acpi_desc->dev, "%s flags:%s%s%s%s\n",
+                               nvdimm_name(nvdimm),
+                 mem_flags & ACPI_NFIT_MEM_SAVE_FAILED ? " save_fail" : "",
+                 mem_flags & ACPI_NFIT_MEM_RESTORE_FAILED ? " restore_fail":"",
+                 mem_flags & ACPI_NFIT_MEM_FLUSH_FAILED ? " flush_fail" : "",
+                 mem_flags & ACPI_NFIT_MEM_NOT_ARMED ? " not_armed" : "");
+
+       }
+
+       return nvdimm_bus_check_dimm_count(acpi_desc->nvdimm_bus, dimm_count);
+}
+
+static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc)
+{
+       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
+       const u8 *uuid = to_nfit_uuid(NFIT_DEV_BUS);
+       struct acpi_device *adev;
+       int i;
+
+       nd_desc->cmd_mask = acpi_desc->bus_cmd_force_en;
+       adev = to_acpi_dev(acpi_desc);
+       if (!adev)
+               return;
+
+       for (i = ND_CMD_ARS_CAP; i <= ND_CMD_CLEAR_ERROR; i++)
+               if (acpi_check_dsm(adev->handle, uuid, 1, 1ULL << i))
+                       set_bit(i, &nd_desc->cmd_mask);
+}
+
+static ssize_t range_index_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nd_region *nd_region = to_nd_region(dev);
+       struct nfit_spa *nfit_spa = nd_region_provider_data(nd_region);
+
+       return sprintf(buf, "%d\n", nfit_spa->spa->range_index);
+}
+static DEVICE_ATTR_RO(range_index);
+
+static struct attribute *acpi_nfit_region_attributes[] = {
+       &dev_attr_range_index.attr,
+       NULL,
+};
+
+static struct attribute_group acpi_nfit_region_attribute_group = {
+       .name = "nfit",
+       .attrs = acpi_nfit_region_attributes,
+};
+
+static const struct attribute_group *acpi_nfit_region_attribute_groups[] = {
+       &nd_region_attribute_group,
+       &nd_mapping_attribute_group,
+       &nd_device_attribute_group,
+       &nd_numa_attribute_group,
+       &acpi_nfit_region_attribute_group,
+       NULL,
+};
+
+/* enough info to uniquely specify an interleave set */
+struct nfit_set_info {
+       struct nfit_set_info_map {
+               u64 region_offset;
+               u32 serial_number;
+               u32 pad;
+       } mapping[0];
+};
+
+static size_t sizeof_nfit_set_info(int num_mappings)
+{
+       return sizeof(struct nfit_set_info)
+               + num_mappings * sizeof(struct nfit_set_info_map);
+}
+
+static int cmp_map(const void *m0, const void *m1)
+{
+       const struct nfit_set_info_map *map0 = m0;
+       const struct nfit_set_info_map *map1 = m1;
+
+       return memcmp(&map0->region_offset, &map1->region_offset,
+                       sizeof(u64));
+}
+
+/* Retrieve the nth entry referencing this spa */
+static struct acpi_nfit_memory_map *memdev_from_spa(
+               struct acpi_nfit_desc *acpi_desc, u16 range_index, int n)
+{
+       struct nfit_memdev *nfit_memdev;
+
+       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list)
+               if (nfit_memdev->memdev->range_index == range_index)
+                       if (n-- == 0)
+                               return nfit_memdev->memdev;
+       return NULL;
+}
+
+static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc,
+               struct nd_region_desc *ndr_desc,
+               struct acpi_nfit_system_address *spa)
+{
+       int i, spa_type = nfit_spa_type(spa);
+       struct device *dev = acpi_desc->dev;
+       struct nd_interleave_set *nd_set;
+       u16 nr = ndr_desc->num_mappings;
+       struct nfit_set_info *info;
+
+       if (spa_type == NFIT_SPA_PM || spa_type == NFIT_SPA_VOLATILE)
+               /* pass */;
+       else
+               return 0;
+
+       nd_set = devm_kzalloc(dev, sizeof(*nd_set), GFP_KERNEL);
+       if (!nd_set)
+               return -ENOMEM;
+
+       info = devm_kzalloc(dev, sizeof_nfit_set_info(nr), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+       for (i = 0; i < nr; i++) {
+               struct nd_mapping *nd_mapping = &ndr_desc->nd_mapping[i];
+               struct nfit_set_info_map *map = &info->mapping[i];
+               struct nvdimm *nvdimm = nd_mapping->nvdimm;
+               struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
+               struct acpi_nfit_memory_map *memdev = memdev_from_spa(acpi_desc,
+                               spa->range_index, i);
+
+               if (!memdev || !nfit_mem->dcr) {
+                       dev_err(dev, "%s: failed to find DCR\n", __func__);
+                       return -ENODEV;
+               }
+
+               map->region_offset = memdev->region_offset;
+               map->serial_number = nfit_mem->dcr->serial_number;
+       }
+
+       sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map),
+                       cmp_map, NULL);
+       nd_set->cookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0);
+       ndr_desc->nd_set = nd_set;
+       devm_kfree(dev, info);
+
+       return 0;
+}
+
+static u64 to_interleave_offset(u64 offset, struct nfit_blk_mmio *mmio)
+{
+       struct acpi_nfit_interleave *idt = mmio->idt;
+       u32 sub_line_offset, line_index, line_offset;
+       u64 line_no, table_skip_count, table_offset;
+
+       line_no = div_u64_rem(offset, mmio->line_size, &sub_line_offset);
+       table_skip_count = div_u64_rem(line_no, mmio->num_lines, &line_index);
+       line_offset = idt->line_offset[line_index]
+               * mmio->line_size;
+       table_offset = table_skip_count * mmio->table_size;
+
+       return mmio->base_offset + line_offset + table_offset + sub_line_offset;
+}
+
+static u32 read_blk_stat(struct nfit_blk *nfit_blk, unsigned int bw)
+{
+       struct nfit_blk_mmio *mmio = &nfit_blk->mmio[DCR];
+       u64 offset = nfit_blk->stat_offset + mmio->size * bw;
+
+       if (mmio->num_lines)
+               offset = to_interleave_offset(offset, mmio);
+
+       return readl(mmio->addr.base + offset);
+}
+
+static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw,
+               resource_size_t dpa, unsigned int len, unsigned int write)
+{
+       u64 cmd, offset;
+       struct nfit_blk_mmio *mmio = &nfit_blk->mmio[DCR];
+
+       enum {
+               BCW_OFFSET_MASK = (1ULL << 48)-1,
+               BCW_LEN_SHIFT = 48,
+               BCW_LEN_MASK = (1ULL << 8) - 1,
+               BCW_CMD_SHIFT = 56,
+       };
+
+       cmd = (dpa >> L1_CACHE_SHIFT) & BCW_OFFSET_MASK;
+       len = len >> L1_CACHE_SHIFT;
+       cmd |= ((u64) len & BCW_LEN_MASK) << BCW_LEN_SHIFT;
+       cmd |= ((u64) write) << BCW_CMD_SHIFT;
+
+       offset = nfit_blk->cmd_offset + mmio->size * bw;
+       if (mmio->num_lines)
+               offset = to_interleave_offset(offset, mmio);
+
+       writeq(cmd, mmio->addr.base + offset);
+       nvdimm_flush(nfit_blk->nd_region);
+
+       if (nfit_blk->dimm_flags & NFIT_BLK_DCR_LATCH)
+               readq(mmio->addr.base + offset);
+}
+
+static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk,
+               resource_size_t dpa, void *iobuf, size_t len, int rw,
+               unsigned int lane)
+{
+       struct nfit_blk_mmio *mmio = &nfit_blk->mmio[BDW];
+       unsigned int copied = 0;
+       u64 base_offset;
+       int rc;
+
+       base_offset = nfit_blk->bdw_offset + dpa % L1_CACHE_BYTES
+               + lane * mmio->size;
+       write_blk_ctl(nfit_blk, lane, dpa, len, rw);
+       while (len) {
+               unsigned int c;
+               u64 offset;
+
+               if (mmio->num_lines) {
+                       u32 line_offset;
+
+                       offset = to_interleave_offset(base_offset + copied,
+                                       mmio);
+                       div_u64_rem(offset, mmio->line_size, &line_offset);
+                       c = min_t(size_t, len, mmio->line_size - line_offset);
+               } else {
+                       offset = base_offset + nfit_blk->bdw_offset;
+                       c = len;
+               }
+
+               if (rw)
+                       memcpy_to_pmem(mmio->addr.aperture + offset,
+                                       iobuf + copied, c);
+               else {
+                       if (nfit_blk->dimm_flags & NFIT_BLK_READ_FLUSH)
+                               mmio_flush_range((void __force *)
+                                       mmio->addr.aperture + offset, c);
+
+                       memcpy_from_pmem(iobuf + copied,
+                                       mmio->addr.aperture + offset, c);
+               }
+
+               copied += c;
+               len -= c;
+       }
+
+       if (rw)
+               nvdimm_flush(nfit_blk->nd_region);
+
+       rc = read_blk_stat(nfit_blk, lane) ? -EIO : 0;
+       return rc;
+}
+
+static int acpi_nfit_blk_region_do_io(struct nd_blk_region *ndbr,
+               resource_size_t dpa, void *iobuf, u64 len, int rw)
+{
+       struct nfit_blk *nfit_blk = nd_blk_region_provider_data(ndbr);
+       struct nfit_blk_mmio *mmio = &nfit_blk->mmio[BDW];
+       struct nd_region *nd_region = nfit_blk->nd_region;
+       unsigned int lane, copied = 0;
+       int rc = 0;
+
+       lane = nd_region_acquire_lane(nd_region);
+       while (len) {
+               u64 c = min(len, mmio->size);
+
+               rc = acpi_nfit_blk_single_io(nfit_blk, dpa + copied,
+                               iobuf + copied, c, rw, lane);
+               if (rc)
+                       break;
+
+               copied += c;
+               len -= c;
+       }
+       nd_region_release_lane(nd_region, lane);
+
+       return rc;
+}
+
+static int nfit_blk_init_interleave(struct nfit_blk_mmio *mmio,
+               struct acpi_nfit_interleave *idt, u16 interleave_ways)
+{
+       if (idt) {
+               mmio->num_lines = idt->line_count;
+               mmio->line_size = idt->line_size;
+               if (interleave_ways == 0)
+                       return -ENXIO;
+               mmio->table_size = mmio->num_lines * interleave_ways
+                       * mmio->line_size;
+       }
+
+       return 0;
+}
+
+static int acpi_nfit_blk_get_flags(struct nvdimm_bus_descriptor *nd_desc,
+               struct nvdimm *nvdimm, struct nfit_blk *nfit_blk)
+{
+       struct nd_cmd_dimm_flags flags;
+       int rc;
+
+       memset(&flags, 0, sizeof(flags));
+       rc = nd_desc->ndctl(nd_desc, nvdimm, ND_CMD_DIMM_FLAGS, &flags,
+                       sizeof(flags), NULL);
+
+       if (rc >= 0 && flags.status == 0)
+               nfit_blk->dimm_flags = flags.flags;
+       else if (rc == -ENOTTY) {
+               /* fall back to a conservative default */
+               nfit_blk->dimm_flags = NFIT_BLK_DCR_LATCH | NFIT_BLK_READ_FLUSH;
+               rc = 0;
+       } else
+               rc = -ENXIO;
+
+       return rc;
+}
+
+static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus,
+               struct device *dev)
+{
+       struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
+       struct nd_blk_region *ndbr = to_nd_blk_region(dev);
+       struct nfit_blk_mmio *mmio;
+       struct nfit_blk *nfit_blk;
+       struct nfit_mem *nfit_mem;
+       struct nvdimm *nvdimm;
+       int rc;
+
+       nvdimm = nd_blk_region_to_dimm(ndbr);
+       nfit_mem = nvdimm_provider_data(nvdimm);
+       if (!nfit_mem || !nfit_mem->dcr || !nfit_mem->bdw) {
+               dev_dbg(dev, "%s: missing%s%s%s\n", __func__,
+                               nfit_mem ? "" : " nfit_mem",
+                               (nfit_mem && nfit_mem->dcr) ? "" : " dcr",
+                               (nfit_mem && nfit_mem->bdw) ? "" : " bdw");
+               return -ENXIO;
+       }
+
+       nfit_blk = devm_kzalloc(dev, sizeof(*nfit_blk), GFP_KERNEL);
+       if (!nfit_blk)
+               return -ENOMEM;
+       nd_blk_region_set_provider_data(ndbr, nfit_blk);
+       nfit_blk->nd_region = to_nd_region(dev);
+
+       /* map block aperture memory */
+       nfit_blk->bdw_offset = nfit_mem->bdw->offset;
+       mmio = &nfit_blk->mmio[BDW];
+       mmio->addr.base = devm_nvdimm_memremap(dev, nfit_mem->spa_bdw->address,
+                        nfit_mem->spa_bdw->length, ARCH_MEMREMAP_PMEM);
+       if (!mmio->addr.base) {
+               dev_dbg(dev, "%s: %s failed to map bdw\n", __func__,
+                               nvdimm_name(nvdimm));
+               return -ENOMEM;
+       }
+       mmio->size = nfit_mem->bdw->size;
+       mmio->base_offset = nfit_mem->memdev_bdw->region_offset;
+       mmio->idt = nfit_mem->idt_bdw;
+       mmio->spa = nfit_mem->spa_bdw;
+       rc = nfit_blk_init_interleave(mmio, nfit_mem->idt_bdw,
+                       nfit_mem->memdev_bdw->interleave_ways);
+       if (rc) {
+               dev_dbg(dev, "%s: %s failed to init bdw interleave\n",
+                               __func__, nvdimm_name(nvdimm));
+               return rc;
+       }
+
+       /* map block control memory */
+       nfit_blk->cmd_offset = nfit_mem->dcr->command_offset;
+       nfit_blk->stat_offset = nfit_mem->dcr->status_offset;
+       mmio = &nfit_blk->mmio[DCR];
+       mmio->addr.base = devm_nvdimm_ioremap(dev, nfit_mem->spa_dcr->address,
+                       nfit_mem->spa_dcr->length);
+       if (!mmio->addr.base) {
+               dev_dbg(dev, "%s: %s failed to map dcr\n", __func__,
+                               nvdimm_name(nvdimm));
+               return -ENOMEM;
+       }
+       mmio->size = nfit_mem->dcr->window_size;
+       mmio->base_offset = nfit_mem->memdev_dcr->region_offset;
+       mmio->idt = nfit_mem->idt_dcr;
+       mmio->spa = nfit_mem->spa_dcr;
+       rc = nfit_blk_init_interleave(mmio, nfit_mem->idt_dcr,
+                       nfit_mem->memdev_dcr->interleave_ways);
+       if (rc) {
+               dev_dbg(dev, "%s: %s failed to init dcr interleave\n",
+                               __func__, nvdimm_name(nvdimm));
+               return rc;
+       }
+
+       rc = acpi_nfit_blk_get_flags(nd_desc, nvdimm, nfit_blk);
+       if (rc < 0) {
+               dev_dbg(dev, "%s: %s failed get DIMM flags\n",
+                               __func__, nvdimm_name(nvdimm));
+               return rc;
+       }
+
+       if (nvdimm_has_flush(nfit_blk->nd_region) < 0)
+               dev_warn(dev, "unable to guarantee persistence of writes\n");
+
+       if (mmio->line_size == 0)
+               return 0;
+
+       if ((u32) nfit_blk->cmd_offset % mmio->line_size
+                       + 8 > mmio->line_size) {
+               dev_dbg(dev, "cmd_offset crosses interleave boundary\n");
+               return -ENXIO;
+       } else if ((u32) nfit_blk->stat_offset % mmio->line_size
+                       + 8 > mmio->line_size) {
+               dev_dbg(dev, "stat_offset crosses interleave boundary\n");
+               return -ENXIO;
+       }
+
+       return 0;
+}
+
+static int ars_get_cap(struct acpi_nfit_desc *acpi_desc,
+               struct nd_cmd_ars_cap *cmd, struct nfit_spa *nfit_spa)
+{
+       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
+       struct acpi_nfit_system_address *spa = nfit_spa->spa;
+       int cmd_rc, rc;
+
+       cmd->address = spa->address;
+       cmd->length = spa->length;
+       rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_CAP, cmd,
+                       sizeof(*cmd), &cmd_rc);
+       if (rc < 0)
+               return rc;
+       return cmd_rc;
+}
+
+static int ars_start(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa)
+{
+       int rc;
+       int cmd_rc;
+       struct nd_cmd_ars_start ars_start;
+       struct acpi_nfit_system_address *spa = nfit_spa->spa;
+       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
+
+       memset(&ars_start, 0, sizeof(ars_start));
+       ars_start.address = spa->address;
+       ars_start.length = spa->length;
+       if (nfit_spa_type(spa) == NFIT_SPA_PM)
+               ars_start.type = ND_ARS_PERSISTENT;
+       else if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE)
+               ars_start.type = ND_ARS_VOLATILE;
+       else
+               return -ENOTTY;
+
+       rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_START, &ars_start,
+                       sizeof(ars_start), &cmd_rc);
+
+       if (rc < 0)
+               return rc;
+       return cmd_rc;
+}
+
+static int ars_continue(struct acpi_nfit_desc *acpi_desc)
+{
+       int rc, cmd_rc;
+       struct nd_cmd_ars_start ars_start;
+       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
+       struct nd_cmd_ars_status *ars_status = acpi_desc->ars_status;
+
+       memset(&ars_start, 0, sizeof(ars_start));
+       ars_start.address = ars_status->restart_address;
+       ars_start.length = ars_status->restart_length;
+       ars_start.type = ars_status->type;
+       rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_START, &ars_start,
+                       sizeof(ars_start), &cmd_rc);
+       if (rc < 0)
+               return rc;
+       return cmd_rc;
+}
+
+static int ars_get_status(struct acpi_nfit_desc *acpi_desc)
+{
+       struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
+       struct nd_cmd_ars_status *ars_status = acpi_desc->ars_status;
+       int rc, cmd_rc;
+
+       rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_STATUS, ars_status,
+                       acpi_desc->ars_status_size, &cmd_rc);
+       if (rc < 0)
+               return rc;
+       return cmd_rc;
+}
+
+static int ars_status_process_records(struct nvdimm_bus *nvdimm_bus,
+               struct nd_cmd_ars_status *ars_status)
+{
+       int rc;
+       u32 i;
+
+       for (i = 0; i < ars_status->num_records; i++) {
+               rc = nvdimm_bus_add_poison(nvdimm_bus,
+                               ars_status->records[i].err_address,
+                               ars_status->records[i].length);
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
+
+static void acpi_nfit_remove_resource(void *data)
+{
+       struct resource *res = data;
+
+       remove_resource(res);
+}
+
+static int acpi_nfit_insert_resource(struct acpi_nfit_desc *acpi_desc,
+               struct nd_region_desc *ndr_desc)
+{
+       struct resource *res, *nd_res = ndr_desc->res;
+       int is_pmem, ret;
+
+       /* No operation if the region is already registered as PMEM */
+       is_pmem = region_intersects(nd_res->start, resource_size(nd_res),
+                               IORESOURCE_MEM, IORES_DESC_PERSISTENT_MEMORY);
+       if (is_pmem == REGION_INTERSECTS)
+               return 0;
+
+       res = devm_kzalloc(acpi_desc->dev, sizeof(*res), GFP_KERNEL);
+       if (!res)
+               return -ENOMEM;
+
+       res->name = "Persistent Memory";
+       res->start = nd_res->start;
+       res->end = nd_res->end;
+       res->flags = IORESOURCE_MEM;
+       res->desc = IORES_DESC_PERSISTENT_MEMORY;
+
+       ret = insert_resource(&iomem_resource, res);
+       if (ret)
+               return ret;
+
+       ret = devm_add_action_or_reset(acpi_desc->dev,
+                                       acpi_nfit_remove_resource,
+                                       res);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int acpi_nfit_init_mapping(struct acpi_nfit_desc *acpi_desc,
+               struct nd_mapping *nd_mapping, struct nd_region_desc *ndr_desc,
+               struct acpi_nfit_memory_map *memdev,
+               struct nfit_spa *nfit_spa)
+{
+       struct nvdimm *nvdimm = acpi_nfit_dimm_by_handle(acpi_desc,
+                       memdev->device_handle);
+       struct acpi_nfit_system_address *spa = nfit_spa->spa;
+       struct nd_blk_region_desc *ndbr_desc;
+       struct nfit_mem *nfit_mem;
+       int blk_valid = 0;
+
+       if (!nvdimm) {
+               dev_err(acpi_desc->dev, "spa%d dimm: %#x not found\n",
+                               spa->range_index, memdev->device_handle);
+               return -ENODEV;
+       }
+
+       nd_mapping->nvdimm = nvdimm;
+       switch (nfit_spa_type(spa)) {
+       case NFIT_SPA_PM:
+       case NFIT_SPA_VOLATILE:
+               nd_mapping->start = memdev->address;
+               nd_mapping->size = memdev->region_size;
+               break;
+       case NFIT_SPA_DCR:
+               nfit_mem = nvdimm_provider_data(nvdimm);
+               if (!nfit_mem || !nfit_mem->bdw) {
+                       dev_dbg(acpi_desc->dev, "spa%d %s missing bdw\n",
+                                       spa->range_index, nvdimm_name(nvdimm));
+               } else {
+                       nd_mapping->size = nfit_mem->bdw->capacity;
+                       nd_mapping->start = nfit_mem->bdw->start_address;
+                       ndr_desc->num_lanes = nfit_mem->bdw->windows;
+                       blk_valid = 1;
+               }
+
+               ndr_desc->nd_mapping = nd_mapping;
+               ndr_desc->num_mappings = blk_valid;
+               ndbr_desc = to_blk_region_desc(ndr_desc);
+               ndbr_desc->enable = acpi_nfit_blk_region_enable;
+               ndbr_desc->do_io = acpi_desc->blk_do_io;
+               nfit_spa->nd_region = nvdimm_blk_region_create(acpi_desc->nvdimm_bus,
+                               ndr_desc);
+               if (!nfit_spa->nd_region)
+                       return -ENOMEM;
+               break;
+       }
+
+       return 0;
+}
+
+static bool nfit_spa_is_virtual(struct acpi_nfit_system_address *spa)
+{
+       return (nfit_spa_type(spa) == NFIT_SPA_VDISK ||
+               nfit_spa_type(spa) == NFIT_SPA_VCD   ||
+               nfit_spa_type(spa) == NFIT_SPA_PDISK ||
+               nfit_spa_type(spa) == NFIT_SPA_PCD);
+}
+
+static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_spa *nfit_spa)
+{
+       static struct nd_mapping nd_mappings[ND_MAX_MAPPINGS];
+       struct acpi_nfit_system_address *spa = nfit_spa->spa;
+       struct nd_blk_region_desc ndbr_desc;
+       struct nd_region_desc *ndr_desc;
+       struct nfit_memdev *nfit_memdev;
+       struct nvdimm_bus *nvdimm_bus;
+       struct resource res;
+       int count = 0, rc;
+
+       if (nfit_spa->nd_region)
+               return 0;
+
+       if (spa->range_index == 0 && !nfit_spa_is_virtual(spa)) {
+               dev_dbg(acpi_desc->dev, "%s: detected invalid spa index\n",
+                               __func__);
+               return 0;
+       }
+
+       memset(&res, 0, sizeof(res));
+       memset(&nd_mappings, 0, sizeof(nd_mappings));
+       memset(&ndbr_desc, 0, sizeof(ndbr_desc));
+       res.start = spa->address;
+       res.end = res.start + spa->length - 1;
+       ndr_desc = &ndbr_desc.ndr_desc;
+       ndr_desc->res = &res;
+       ndr_desc->provider_data = nfit_spa;
+       ndr_desc->attr_groups = acpi_nfit_region_attribute_groups;
+       if (spa->flags & ACPI_NFIT_PROXIMITY_VALID)
+               ndr_desc->numa_node = acpi_map_pxm_to_online_node(
+                                               spa->proximity_domain);
+       else
+               ndr_desc->numa_node = NUMA_NO_NODE;
+
+       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
+               struct acpi_nfit_memory_map *memdev = nfit_memdev->memdev;
+               struct nd_mapping *nd_mapping;
+
+               if (memdev->range_index != spa->range_index)
+                       continue;
+               if (count >= ND_MAX_MAPPINGS) {
+                       dev_err(acpi_desc->dev, "spa%d exceeds max mappings %d\n",
+                                       spa->range_index, ND_MAX_MAPPINGS);
+                       return -ENXIO;
+               }
+               nd_mapping = &nd_mappings[count++];
+               rc = acpi_nfit_init_mapping(acpi_desc, nd_mapping, ndr_desc,
+                               memdev, nfit_spa);
+               if (rc)
+                       goto out;
+       }
+
+       ndr_desc->nd_mapping = nd_mappings;
+       ndr_desc->num_mappings = count;
+       rc = acpi_nfit_init_interleave_set(acpi_desc, ndr_desc, spa);
+       if (rc)
+               goto out;
+
+       nvdimm_bus = acpi_desc->nvdimm_bus;
+       if (nfit_spa_type(spa) == NFIT_SPA_PM) {
+               rc = acpi_nfit_insert_resource(acpi_desc, ndr_desc);
+               if (rc) {
+                       dev_warn(acpi_desc->dev,
+                               "failed to insert pmem resource to iomem: %d\n",
+                               rc);
+                       goto out;
+               }
+
+               nfit_spa->nd_region = nvdimm_pmem_region_create(nvdimm_bus,
+                               ndr_desc);
+               if (!nfit_spa->nd_region)
+                       rc = -ENOMEM;
+       } else if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE) {
+               nfit_spa->nd_region = nvdimm_volatile_region_create(nvdimm_bus,
+                               ndr_desc);
+               if (!nfit_spa->nd_region)
+                       rc = -ENOMEM;
+       } else if (nfit_spa_is_virtual(spa)) {
+               nfit_spa->nd_region = nvdimm_pmem_region_create(nvdimm_bus,
+                               ndr_desc);
+               if (!nfit_spa->nd_region)
+                       rc = -ENOMEM;
+       }
+
+ out:
+       if (rc)
+               dev_err(acpi_desc->dev, "failed to register spa range %d\n",
+                               nfit_spa->spa->range_index);
+       return rc;
+}
+
+static int ars_status_alloc(struct acpi_nfit_desc *acpi_desc,
+               u32 max_ars)
+{
+       struct device *dev = acpi_desc->dev;
+       struct nd_cmd_ars_status *ars_status;
+
+       if (acpi_desc->ars_status && acpi_desc->ars_status_size >= max_ars) {
+               memset(acpi_desc->ars_status, 0, acpi_desc->ars_status_size);
+               return 0;
+       }
+
+       if (acpi_desc->ars_status)
+               devm_kfree(dev, acpi_desc->ars_status);
+       acpi_desc->ars_status = NULL;
+       ars_status = devm_kzalloc(dev, max_ars, GFP_KERNEL);
+       if (!ars_status)
+               return -ENOMEM;
+       acpi_desc->ars_status = ars_status;
+       acpi_desc->ars_status_size = max_ars;
+       return 0;
+}
+
+static int acpi_nfit_query_poison(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_spa *nfit_spa)
+{
+       struct acpi_nfit_system_address *spa = nfit_spa->spa;
+       int rc;
+
+       if (!nfit_spa->max_ars) {
+               struct nd_cmd_ars_cap ars_cap;
+
+               memset(&ars_cap, 0, sizeof(ars_cap));
+               rc = ars_get_cap(acpi_desc, &ars_cap, nfit_spa);
+               if (rc < 0)
+                       return rc;
+               nfit_spa->max_ars = ars_cap.max_ars_out;
+               nfit_spa->clear_err_unit = ars_cap.clear_err_unit;
+               /* check that the supported scrub types match the spa type */
+               if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE &&
+                               ((ars_cap.status >> 16) & ND_ARS_VOLATILE) == 0)
+                       return -ENOTTY;
+               else if (nfit_spa_type(spa) == NFIT_SPA_PM &&
+                               ((ars_cap.status >> 16) & ND_ARS_PERSISTENT) == 0)
+                       return -ENOTTY;
+       }
+
+       if (ars_status_alloc(acpi_desc, nfit_spa->max_ars))
+               return -ENOMEM;
+
+       rc = ars_get_status(acpi_desc);
+       if (rc < 0 && rc != -ENOSPC)
+               return rc;
+
+       if (ars_status_process_records(acpi_desc->nvdimm_bus,
+                               acpi_desc->ars_status))
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void acpi_nfit_async_scrub(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_spa *nfit_spa)
+{
+       struct acpi_nfit_system_address *spa = nfit_spa->spa;
+       unsigned int overflow_retry = scrub_overflow_abort;
+       u64 init_ars_start = 0, init_ars_len = 0;
+       struct device *dev = acpi_desc->dev;
+       unsigned int tmo = scrub_timeout;
+       int rc;
+
+       if (!nfit_spa->ars_required || !nfit_spa->nd_region)
+               return;
+
+       rc = ars_start(acpi_desc, nfit_spa);
+       /*
+        * If we timed out the initial scan we'll still be busy here,
+        * and will wait another timeout before giving up permanently.
+        */
+       if (rc < 0 && rc != -EBUSY)
+               return;
+
+       do {
+               u64 ars_start, ars_len;
+
+               if (acpi_desc->cancel)
+                       break;
+               rc = acpi_nfit_query_poison(acpi_desc, nfit_spa);
+               if (rc == -ENOTTY)
+                       break;
+               if (rc == -EBUSY && !tmo) {
+                       dev_warn(dev, "range %d ars timeout, aborting\n",
+                                       spa->range_index);
+                       break;
+               }
+
+               if (rc == -EBUSY) {
+                       /*
+                        * Note, entries may be appended to the list
+                        * while the lock is dropped, but the workqueue
+                        * being active prevents entries being deleted /
+                        * freed.
+                        */
+                       mutex_unlock(&acpi_desc->init_mutex);
+                       ssleep(1);
+                       tmo--;
+                       mutex_lock(&acpi_desc->init_mutex);
+                       continue;
+               }
+
+               /* we got some results, but there are more pending... */
+               if (rc == -ENOSPC && overflow_retry--) {
+                       if (!init_ars_len) {
+                               init_ars_len = acpi_desc->ars_status->length;
+                               init_ars_start = acpi_desc->ars_status->address;
+                       }
+                       rc = ars_continue(acpi_desc);
+               }
+
+               if (rc < 0) {
+                       dev_warn(dev, "range %d ars continuation failed\n",
+                                       spa->range_index);
+                       break;
+               }
+
+               if (init_ars_len) {
+                       ars_start = init_ars_start;
+                       ars_len = init_ars_len;
+               } else {
+                       ars_start = acpi_desc->ars_status->address;
+                       ars_len = acpi_desc->ars_status->length;
+               }
+               dev_dbg(dev, "spa range: %d ars from %#llx + %#llx complete\n",
+                               spa->range_index, ars_start, ars_len);
+               /* notify the region about new poison entries */
+               nvdimm_region_notify(nfit_spa->nd_region,
+                               NVDIMM_REVALIDATE_POISON);
+               break;
+       } while (1);
+}
+
+static void acpi_nfit_scrub(struct work_struct *work)
+{
+       struct device *dev;
+       u64 init_scrub_length = 0;
+       struct nfit_spa *nfit_spa;
+       u64 init_scrub_address = 0;
+       bool init_ars_done = false;
+       struct acpi_nfit_desc *acpi_desc;
+       unsigned int tmo = scrub_timeout;
+       unsigned int overflow_retry = scrub_overflow_abort;
+
+       acpi_desc = container_of(work, typeof(*acpi_desc), work);
+       dev = acpi_desc->dev;
+
+       /*
+        * We scrub in 2 phases.  The first phase waits for any platform
+        * firmware initiated scrubs to complete and then we go search for the
+        * affected spa regions to mark them scanned.  In the second phase we
+        * initiate a directed scrub for every range that was not scrubbed in
+        * phase 1. If we're called for a 'rescan', we harmlessly pass through
+        * the first phase, but really only care about running phase 2, where
+        * regions can be notified of new poison.
+        */
+
+       /* process platform firmware initiated scrubs */
+ retry:
+       mutex_lock(&acpi_desc->init_mutex);
+       list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
+               struct nd_cmd_ars_status *ars_status;
+               struct acpi_nfit_system_address *spa;
+               u64 ars_start, ars_len;
+               int rc;
+
+               if (acpi_desc->cancel)
+                       break;
+
+               if (nfit_spa->nd_region)
+                       continue;
+
+               if (init_ars_done) {
+                       /*
+                        * No need to re-query, we're now just
+                        * reconciling all the ranges covered by the
+                        * initial scrub
+                        */
+                       rc = 0;
+               } else
+                       rc = acpi_nfit_query_poison(acpi_desc, nfit_spa);
+
+               if (rc == -ENOTTY) {
+                       /* no ars capability, just register spa and move on */
+                       acpi_nfit_register_region(acpi_desc, nfit_spa);
+                       continue;
+               }
+
+               if (rc == -EBUSY && !tmo) {
+                       /* fallthrough to directed scrub in phase 2 */
+                       dev_warn(dev, "timeout awaiting ars results, continuing...\n");
+                       break;
+               } else if (rc == -EBUSY) {
+                       mutex_unlock(&acpi_desc->init_mutex);
+                       ssleep(1);
+                       tmo--;
+                       goto retry;
+               }
+
+               /* we got some results, but there are more pending... */
+               if (rc == -ENOSPC && overflow_retry--) {
+                       ars_status = acpi_desc->ars_status;
+                       /*
+                        * Record the original scrub range, so that we
+                        * can recall all the ranges impacted by the
+                        * initial scrub.
+                        */
+                       if (!init_scrub_length) {
+                               init_scrub_length = ars_status->length;
+                               init_scrub_address = ars_status->address;
+                       }
+                       rc = ars_continue(acpi_desc);
+                       if (rc == 0) {
+                               mutex_unlock(&acpi_desc->init_mutex);
+                               goto retry;
+                       }
+               }
+
+               if (rc < 0) {
+                       /*
+                        * Initial scrub failed, we'll give it one more
+                        * try below...
+                        */
+                       break;
+               }
+
+               /* We got some final results, record completed ranges */
+               ars_status = acpi_desc->ars_status;
+               if (init_scrub_length) {
+                       ars_start = init_scrub_address;
+                       ars_len = ars_start + init_scrub_length;
+               } else {
+                       ars_start = ars_status->address;
+                       ars_len = ars_status->length;
+               }
+               spa = nfit_spa->spa;
+
+               if (!init_ars_done) {
+                       init_ars_done = true;
+                       dev_dbg(dev, "init scrub %#llx + %#llx complete\n",
+                                       ars_start, ars_len);
+               }
+               if (ars_start <= spa->address && ars_start + ars_len
+                               >= spa->address + spa->length)
+                       acpi_nfit_register_region(acpi_desc, nfit_spa);
+       }
+
+       /*
+        * For all the ranges not covered by an initial scrub we still
+        * want to see if there are errors, but it's ok to discover them
+        * asynchronously.
+        */
+       list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
+               /*
+                * Flag all the ranges that still need scrubbing, but
+                * register them now to make data available.
+                */
+               if (!nfit_spa->nd_region) {
+                       nfit_spa->ars_required = 1;
+                       acpi_nfit_register_region(acpi_desc, nfit_spa);
+               }
+       }
+
+       list_for_each_entry(nfit_spa, &acpi_desc->spas, list)
+               acpi_nfit_async_scrub(acpi_desc, nfit_spa);
+       acpi_desc->scrub_count++;
+       if (acpi_desc->scrub_count_state)
+               sysfs_notify_dirent(acpi_desc->scrub_count_state);
+       mutex_unlock(&acpi_desc->init_mutex);
+}
+
+static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc)
+{
+       struct nfit_spa *nfit_spa;
+       int rc;
+
+       list_for_each_entry(nfit_spa, &acpi_desc->spas, list)
+               if (nfit_spa_type(nfit_spa->spa) == NFIT_SPA_DCR) {
+                       /* BLK regions don't need to wait for ars results */
+                       rc = acpi_nfit_register_region(acpi_desc, nfit_spa);
+                       if (rc)
+                               return rc;
+               }
+
+       queue_work(nfit_wq, &acpi_desc->work);
+       return 0;
+}
+
+static int acpi_nfit_check_deletions(struct acpi_nfit_desc *acpi_desc,
+               struct nfit_table_prev *prev)
+{
+       struct device *dev = acpi_desc->dev;
+
+       if (!list_empty(&prev->spas) ||
+                       !list_empty(&prev->memdevs) ||
+                       !list_empty(&prev->dcrs) ||
+                       !list_empty(&prev->bdws) ||
+                       !list_empty(&prev->idts) ||
+                       !list_empty(&prev->flushes)) {
+               dev_err(dev, "new nfit deletes entries (unsupported)\n");
+               return -ENXIO;
+       }
+       return 0;
+}
+
+static int acpi_nfit_desc_init_scrub_attr(struct acpi_nfit_desc *acpi_desc)
+{
+       struct device *dev = acpi_desc->dev;
+       struct kernfs_node *nfit;
+       struct device *bus_dev;
+
+       if (!ars_supported(acpi_desc->nvdimm_bus))
+               return 0;
+
+       bus_dev = to_nvdimm_bus_dev(acpi_desc->nvdimm_bus);
+       nfit = sysfs_get_dirent(bus_dev->kobj.sd, "nfit");
+       if (!nfit) {
+               dev_err(dev, "sysfs_get_dirent 'nfit' failed\n");
+               return -ENODEV;
+       }
+       acpi_desc->scrub_count_state = sysfs_get_dirent(nfit, "scrub");
+       sysfs_put(nfit);
+       if (!acpi_desc->scrub_count_state) {
+               dev_err(dev, "sysfs_get_dirent 'scrub' failed\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void acpi_nfit_destruct(void *data)
+{
+       struct acpi_nfit_desc *acpi_desc = data;
+       struct device *bus_dev = to_nvdimm_bus_dev(acpi_desc->nvdimm_bus);
+
+       /*
+        * Destruct under acpi_desc_lock so that nfit_handle_mce does not
+        * race teardown
+        */
+       mutex_lock(&acpi_desc_lock);
+       acpi_desc->cancel = 1;
+       /*
+        * Bounce the nvdimm bus lock to make sure any in-flight
+        * acpi_nfit_ars_rescan() submissions have had a chance to
+        * either submit or see ->cancel set.
+        */
+       device_lock(bus_dev);
+       device_unlock(bus_dev);
+
+       flush_workqueue(nfit_wq);
+       if (acpi_desc->scrub_count_state)
+               sysfs_put(acpi_desc->scrub_count_state);
+       nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
+       acpi_desc->nvdimm_bus = NULL;
+       list_del(&acpi_desc->list);
+       mutex_unlock(&acpi_desc_lock);
+}
+
+int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *data, acpi_size sz)
+{
+       struct device *dev = acpi_desc->dev;
+       struct nfit_table_prev prev;
+       const void *end;
+       int rc;
+
+       if (!acpi_desc->nvdimm_bus) {
+               acpi_nfit_init_dsms(acpi_desc);
+
+               acpi_desc->nvdimm_bus = nvdimm_bus_register(dev,
+                               &acpi_desc->nd_desc);
+               if (!acpi_desc->nvdimm_bus)
+                       return -ENOMEM;
+
+               rc = devm_add_action_or_reset(dev, acpi_nfit_destruct,
+                               acpi_desc);
+               if (rc)
+                       return rc;
+
+               rc = acpi_nfit_desc_init_scrub_attr(acpi_desc);
+               if (rc)
+                       return rc;
+
+               /* register this acpi_desc for mce notifications */
+               mutex_lock(&acpi_desc_lock);
+               list_add_tail(&acpi_desc->list, &acpi_descs);
+               mutex_unlock(&acpi_desc_lock);
+       }
+
+       mutex_lock(&acpi_desc->init_mutex);
+
+       INIT_LIST_HEAD(&prev.spas);
+       INIT_LIST_HEAD(&prev.memdevs);
+       INIT_LIST_HEAD(&prev.dcrs);
+       INIT_LIST_HEAD(&prev.bdws);
+       INIT_LIST_HEAD(&prev.idts);
+       INIT_LIST_HEAD(&prev.flushes);
+
+       list_cut_position(&prev.spas, &acpi_desc->spas,
+                               acpi_desc->spas.prev);
+       list_cut_position(&prev.memdevs, &acpi_desc->memdevs,
+                               acpi_desc->memdevs.prev);
+       list_cut_position(&prev.dcrs, &acpi_desc->dcrs,
+                               acpi_desc->dcrs.prev);
+       list_cut_position(&prev.bdws, &acpi_desc->bdws,
+                               acpi_desc->bdws.prev);
+       list_cut_position(&prev.idts, &acpi_desc->idts,
+                               acpi_desc->idts.prev);
+       list_cut_position(&prev.flushes, &acpi_desc->flushes,
+                               acpi_desc->flushes.prev);
+
+       end = data + sz;
+       while (!IS_ERR_OR_NULL(data))
+               data = add_table(acpi_desc, &prev, data, end);
+
+       if (IS_ERR(data)) {
+               dev_dbg(dev, "%s: nfit table parsing error: %ld\n", __func__,
+                               PTR_ERR(data));
+               rc = PTR_ERR(data);
+               goto out_unlock;
+       }
+
+       rc = acpi_nfit_check_deletions(acpi_desc, &prev);
+       if (rc)
+               goto out_unlock;
+
+       rc = nfit_mem_init(acpi_desc);
+       if (rc)
+               goto out_unlock;
+
+       rc = acpi_nfit_register_dimms(acpi_desc);
+       if (rc)
+               goto out_unlock;
+
+       rc = acpi_nfit_register_regions(acpi_desc);
+
+ out_unlock:
+       mutex_unlock(&acpi_desc->init_mutex);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(acpi_nfit_init);
+
+struct acpi_nfit_flush_work {
+       struct work_struct work;
+       struct completion cmp;
+};
+
+static void flush_probe(struct work_struct *work)
+{
+       struct acpi_nfit_flush_work *flush;
+
+       flush = container_of(work, typeof(*flush), work);
+       complete(&flush->cmp);
+}
+
+static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc)
+{
+       struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
+       struct device *dev = acpi_desc->dev;
+       struct acpi_nfit_flush_work flush;
+
+       /* bounce the device lock to flush acpi_nfit_add / acpi_nfit_notify */
+       device_lock(dev);
+       device_unlock(dev);
+
+       /*
+        * Scrub work could take 10s of seconds, userspace may give up so we
+        * need to be interruptible while waiting.
+        */
+       INIT_WORK_ONSTACK(&flush.work, flush_probe);
+       COMPLETION_INITIALIZER_ONSTACK(flush.cmp);
+       queue_work(nfit_wq, &flush.work);
+       return wait_for_completion_interruptible(&flush.cmp);
+}
+
+static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
+               struct nvdimm *nvdimm, unsigned int cmd)
+{
+       struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
+
+       if (nvdimm)
+               return 0;
+       if (cmd != ND_CMD_ARS_START)
+               return 0;
+
+       /*
+        * The kernel and userspace may race to initiate a scrub, but
+        * the scrub thread is prepared to lose that initial race.  It
+        * just needs guarantees that any ars it initiates are not
+        * interrupted by any intervening start reqeusts from userspace.
+        */
+       if (work_busy(&acpi_desc->work))
+               return -EBUSY;
+
+       return 0;
+}
+
+int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc)
+{
+       struct device *dev = acpi_desc->dev;
+       struct nfit_spa *nfit_spa;
+
+       if (work_busy(&acpi_desc->work))
+               return -EBUSY;
+
+       if (acpi_desc->cancel)
+               return 0;
+
+       mutex_lock(&acpi_desc->init_mutex);
+       list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
+               struct acpi_nfit_system_address *spa = nfit_spa->spa;
+
+               if (nfit_spa_type(spa) != NFIT_SPA_PM)
+                       continue;
+
+               nfit_spa->ars_required = 1;
+       }
+       queue_work(nfit_wq, &acpi_desc->work);
+       dev_dbg(dev, "%s: ars_scan triggered\n", __func__);
+       mutex_unlock(&acpi_desc->init_mutex);
+
+       return 0;
+}
+
+void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev)
+{
+       struct nvdimm_bus_descriptor *nd_desc;
+
+       dev_set_drvdata(dev, acpi_desc);
+       acpi_desc->dev = dev;
+       acpi_desc->blk_do_io = acpi_nfit_blk_region_do_io;
+       nd_desc = &acpi_desc->nd_desc;
+       nd_desc->provider_name = "ACPI.NFIT";
+       nd_desc->module = THIS_MODULE;
+       nd_desc->ndctl = acpi_nfit_ctl;
+       nd_desc->flush_probe = acpi_nfit_flush_probe;
+       nd_desc->clear_to_send = acpi_nfit_clear_to_send;
+       nd_desc->attr_groups = acpi_nfit_attribute_groups;
+
+       INIT_LIST_HEAD(&acpi_desc->spas);
+       INIT_LIST_HEAD(&acpi_desc->dcrs);
+       INIT_LIST_HEAD(&acpi_desc->bdws);
+       INIT_LIST_HEAD(&acpi_desc->idts);
+       INIT_LIST_HEAD(&acpi_desc->flushes);
+       INIT_LIST_HEAD(&acpi_desc->memdevs);
+       INIT_LIST_HEAD(&acpi_desc->dimms);
+       INIT_LIST_HEAD(&acpi_desc->list);
+       mutex_init(&acpi_desc->init_mutex);
+       INIT_WORK(&acpi_desc->work, acpi_nfit_scrub);
+}
+EXPORT_SYMBOL_GPL(acpi_nfit_desc_init);
+
+static int acpi_nfit_add(struct acpi_device *adev)
+{
+       struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_nfit_desc *acpi_desc;
+       struct device *dev = &adev->dev;
+       struct acpi_table_header *tbl;
+       acpi_status status = AE_OK;
+       acpi_size sz;
+       int rc = 0;
+
+       status = acpi_get_table_with_size(ACPI_SIG_NFIT, 0, &tbl, &sz);
+       if (ACPI_FAILURE(status)) {
+               /* This is ok, we could have an nvdimm hotplugged later */
+               dev_dbg(dev, "failed to find NFIT at startup\n");
+               return 0;
+       }
+
+       acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL);
+       if (!acpi_desc)
+               return -ENOMEM;
+       acpi_nfit_desc_init(acpi_desc, &adev->dev);
+
+       /* Save the acpi header for exporting the revision via sysfs */
+       acpi_desc->acpi_header = *tbl;
+
+       /* Evaluate _FIT and override with that if present */
+       status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf);
+       if (ACPI_SUCCESS(status) && buf.length > 0) {
+               union acpi_object *obj = buf.pointer;
+
+               if (obj->type == ACPI_TYPE_BUFFER)
+                       rc = acpi_nfit_init(acpi_desc, obj->buffer.pointer,
+                                       obj->buffer.length);
+               else
+                       dev_dbg(dev, "%s invalid type %d, ignoring _FIT\n",
+                                __func__, (int) obj->type);
+               kfree(buf.pointer);
+       } else
+               /* skip over the lead-in header table */
+               rc = acpi_nfit_init(acpi_desc, (void *) tbl
+                               + sizeof(struct acpi_table_nfit),
+                               sz - sizeof(struct acpi_table_nfit));
+       return rc;
+}
+
+static int acpi_nfit_remove(struct acpi_device *adev)
+{
+       /* see acpi_nfit_destruct */
+       return 0;
+}
+
+static void acpi_nfit_notify(struct acpi_device *adev, u32 event)
+{
+       struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(&adev->dev);
+       struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct device *dev = &adev->dev;
+       union acpi_object *obj;
+       acpi_status status;
+       int ret;
+
+       dev_dbg(dev, "%s: event: %d\n", __func__, event);
+
+       device_lock(dev);
+       if (!dev->driver) {
+               /* dev->driver may be null if we're being removed */
+               dev_dbg(dev, "%s: no driver found for dev\n", __func__);
+               goto out_unlock;
+       }
+
+       if (!acpi_desc) {
+               acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL);
+               if (!acpi_desc)
+                       goto out_unlock;
+               acpi_nfit_desc_init(acpi_desc, &adev->dev);
+       } else {
+               /*
+                * Finish previous registration before considering new
+                * regions.
+                */
+               flush_workqueue(nfit_wq);
+       }
+
+       /* Evaluate _FIT */
+       status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf);
+       if (ACPI_FAILURE(status)) {
+               dev_err(dev, "failed to evaluate _FIT\n");
+               goto out_unlock;
+       }
+
+       obj = buf.pointer;
+       if (obj->type == ACPI_TYPE_BUFFER) {
+               ret = acpi_nfit_init(acpi_desc, obj->buffer.pointer,
+                               obj->buffer.length);
+               if (ret)
+                       dev_err(dev, "failed to merge updated NFIT\n");
+       } else
+               dev_err(dev, "Invalid _FIT\n");
+       kfree(buf.pointer);
+
+ out_unlock:
+       device_unlock(dev);
+}
+
+static const struct acpi_device_id acpi_nfit_ids[] = {
+       { "ACPI0012", 0 },
+       { "", 0 },
+};
+MODULE_DEVICE_TABLE(acpi, acpi_nfit_ids);
+
+static struct acpi_driver acpi_nfit_driver = {
+       .name = KBUILD_MODNAME,
+       .ids = acpi_nfit_ids,
+       .ops = {
+               .add = acpi_nfit_add,
+               .remove = acpi_nfit_remove,
+               .notify = acpi_nfit_notify,
+       },
+};
+
+static __init int nfit_init(void)
+{
+       BUILD_BUG_ON(sizeof(struct acpi_table_nfit) != 40);
+       BUILD_BUG_ON(sizeof(struct acpi_nfit_system_address) != 56);
+       BUILD_BUG_ON(sizeof(struct acpi_nfit_memory_map) != 48);
+       BUILD_BUG_ON(sizeof(struct acpi_nfit_interleave) != 20);
+       BUILD_BUG_ON(sizeof(struct acpi_nfit_smbios) != 9);
+       BUILD_BUG_ON(sizeof(struct acpi_nfit_control_region) != 80);
+       BUILD_BUG_ON(sizeof(struct acpi_nfit_data_region) != 40);
+
+       acpi_str_to_uuid(UUID_VOLATILE_MEMORY, nfit_uuid[NFIT_SPA_VOLATILE]);
+       acpi_str_to_uuid(UUID_PERSISTENT_MEMORY, nfit_uuid[NFIT_SPA_PM]);
+       acpi_str_to_uuid(UUID_CONTROL_REGION, nfit_uuid[NFIT_SPA_DCR]);
+       acpi_str_to_uuid(UUID_DATA_REGION, nfit_uuid[NFIT_SPA_BDW]);
+       acpi_str_to_uuid(UUID_VOLATILE_VIRTUAL_DISK, nfit_uuid[NFIT_SPA_VDISK]);
+       acpi_str_to_uuid(UUID_VOLATILE_VIRTUAL_CD, nfit_uuid[NFIT_SPA_VCD]);
+       acpi_str_to_uuid(UUID_PERSISTENT_VIRTUAL_DISK, nfit_uuid[NFIT_SPA_PDISK]);
+       acpi_str_to_uuid(UUID_PERSISTENT_VIRTUAL_CD, nfit_uuid[NFIT_SPA_PCD]);
+       acpi_str_to_uuid(UUID_NFIT_BUS, nfit_uuid[NFIT_DEV_BUS]);
+       acpi_str_to_uuid(UUID_NFIT_DIMM, nfit_uuid[NFIT_DEV_DIMM]);
+       acpi_str_to_uuid(UUID_NFIT_DIMM_N_HPE1, nfit_uuid[NFIT_DEV_DIMM_N_HPE1]);
+       acpi_str_to_uuid(UUID_NFIT_DIMM_N_HPE2, nfit_uuid[NFIT_DEV_DIMM_N_HPE2]);
+       acpi_str_to_uuid(UUID_NFIT_DIMM_N_MSFT, nfit_uuid[NFIT_DEV_DIMM_N_MSFT]);
+
+       nfit_wq = create_singlethread_workqueue("nfit");
+       if (!nfit_wq)
+               return -ENOMEM;
+
+       nfit_mce_register();
+
+       return acpi_bus_register_driver(&acpi_nfit_driver);
+}
+
+static __exit void nfit_exit(void)
+{
+       nfit_mce_unregister();
+       acpi_bus_unregister_driver(&acpi_nfit_driver);
+       destroy_workqueue(nfit_wq);
+       WARN_ON(!list_empty(&acpi_descs));
+}
+
+module_init(nfit_init);
+module_exit(nfit_exit);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Intel Corporation");
diff --git a/drivers/acpi/nfit/mce.c b/drivers/acpi/nfit/mce.c
new file mode 100644 (file)
index 0000000..4c745bf
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * NFIT - Machine Check Handler
+ *
+ * Copyright(c) 2013-2016 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+#include <linux/notifier.h>
+#include <linux/acpi.h>
+#include <asm/mce.h>
+#include "nfit.h"
+
+static int nfit_handle_mce(struct notifier_block *nb, unsigned long val,
+                       void *data)
+{
+       struct mce *mce = (struct mce *)data;
+       struct acpi_nfit_desc *acpi_desc;
+       struct nfit_spa *nfit_spa;
+
+       /* We only care about memory errors */
+       if (!(mce->status & MCACOD))
+               return NOTIFY_DONE;
+
+       /*
+        * mce->addr contains the physical addr accessed that caused the
+        * machine check. We need to walk through the list of NFITs, and see
+        * if any of them matches that address, and only then start a scrub.
+        */
+       mutex_lock(&acpi_desc_lock);
+       list_for_each_entry(acpi_desc, &acpi_descs, list) {
+               struct device *dev = acpi_desc->dev;
+               int found_match = 0;
+
+               mutex_lock(&acpi_desc->init_mutex);
+               list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
+                       struct acpi_nfit_system_address *spa = nfit_spa->spa;
+
+                       if (nfit_spa_type(spa) == NFIT_SPA_PM)
+                               continue;
+                       /* find the spa that covers the mce addr */
+                       if (spa->address > mce->addr)
+                               continue;
+                       if ((spa->address + spa->length - 1) < mce->addr)
+                               continue;
+                       found_match = 1;
+                       dev_dbg(dev, "%s: addr in SPA %d (0x%llx, 0x%llx)\n",
+                               __func__, spa->range_index, spa->address,
+                               spa->length);
+                       /*
+                        * We can break at the first match because we're going
+                        * to rescan all the SPA ranges. There shouldn't be any
+                        * aliasing anyway.
+                        */
+                       break;
+               }
+               mutex_unlock(&acpi_desc->init_mutex);
+
+               /*
+                * We can ignore an -EBUSY here because if an ARS is already
+                * in progress, just let that be the last authoritative one
+                */
+               if (found_match)
+                       acpi_nfit_ars_rescan(acpi_desc);
+       }
+
+       mutex_unlock(&acpi_desc_lock);
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block nfit_mce_dec = {
+       .notifier_call  = nfit_handle_mce,
+};
+
+void nfit_mce_register(void)
+{
+       mce_register_decode_chain(&nfit_mce_dec);
+}
+
+void nfit_mce_unregister(void)
+{
+       mce_unregister_decode_chain(&nfit_mce_dec);
+}
diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h
new file mode 100644 (file)
index 0000000..e894ded
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * NVDIMM Firmware Interface Table - NFIT
+ *
+ * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+#ifndef __NFIT_H__
+#define __NFIT_H__
+#include <linux/workqueue.h>
+#include <linux/libnvdimm.h>
+#include <linux/ndctl.h>
+#include <linux/types.h>
+#include <linux/uuid.h>
+#include <linux/acpi.h>
+#include <acpi/acuuid.h>
+
+/* ACPI 6.1 */
+#define UUID_NFIT_BUS "2f10e7a4-9e91-11e4-89d3-123b93f75cba"
+
+/* http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf */
+#define UUID_NFIT_DIMM "4309ac30-0d11-11e4-9191-0800200c9a66"
+
+/* https://github.com/HewlettPackard/hpe-nvm/blob/master/Documentation/ */
+#define UUID_NFIT_DIMM_N_HPE1 "9002c334-acf3-4c0e-9642-a235f0d53bc6"
+#define UUID_NFIT_DIMM_N_HPE2 "5008664b-b758-41a0-a03c-27c2f2d04f7e"
+
+/* https://msdn.microsoft.com/library/windows/hardware/mt604741 */
+#define UUID_NFIT_DIMM_N_MSFT "1ee68b36-d4bd-4a1a-9a16-4f8e53d46e05"
+
+#define ACPI_NFIT_MEM_FAILED_MASK (ACPI_NFIT_MEM_SAVE_FAILED \
+               | ACPI_NFIT_MEM_RESTORE_FAILED | ACPI_NFIT_MEM_FLUSH_FAILED \
+               | ACPI_NFIT_MEM_NOT_ARMED)
+
+enum nfit_uuids {
+       /* for simplicity alias the uuid index with the family id */
+       NFIT_DEV_DIMM = NVDIMM_FAMILY_INTEL,
+       NFIT_DEV_DIMM_N_HPE1 = NVDIMM_FAMILY_HPE1,
+       NFIT_DEV_DIMM_N_HPE2 = NVDIMM_FAMILY_HPE2,
+       NFIT_DEV_DIMM_N_MSFT = NVDIMM_FAMILY_MSFT,
+       NFIT_SPA_VOLATILE,
+       NFIT_SPA_PM,
+       NFIT_SPA_DCR,
+       NFIT_SPA_BDW,
+       NFIT_SPA_VDISK,
+       NFIT_SPA_VCD,
+       NFIT_SPA_PDISK,
+       NFIT_SPA_PCD,
+       NFIT_DEV_BUS,
+       NFIT_UUID_MAX,
+};
+
+/*
+ * Region format interface codes are stored with the interface as the
+ * LSB and the function as the MSB.
+ */
+#define NFIT_FIC_BYTE cpu_to_le16(0x101) /* byte-addressable energy backed */
+#define NFIT_FIC_BLK cpu_to_le16(0x201) /* block-addressable non-energy backed */
+#define NFIT_FIC_BYTEN cpu_to_le16(0x301) /* byte-addressable non-energy backed */
+
+enum {
+       NFIT_BLK_READ_FLUSH = 1,
+       NFIT_BLK_DCR_LATCH = 2,
+       NFIT_ARS_STATUS_DONE = 0,
+       NFIT_ARS_STATUS_BUSY = 1 << 16,
+       NFIT_ARS_STATUS_NONE = 2 << 16,
+       NFIT_ARS_STATUS_INTR = 3 << 16,
+       NFIT_ARS_START_BUSY = 6,
+       NFIT_ARS_CAP_NONE = 1,
+       NFIT_ARS_F_OVERFLOW = 1,
+       NFIT_ARS_TIMEOUT = 90,
+};
+
+struct nfit_spa {
+       struct list_head list;
+       struct nd_region *nd_region;
+       unsigned int ars_required:1;
+       u32 clear_err_unit;
+       u32 max_ars;
+       struct acpi_nfit_system_address spa[0];
+};
+
+struct nfit_dcr {
+       struct list_head list;
+       struct acpi_nfit_control_region dcr[0];
+};
+
+struct nfit_bdw {
+       struct list_head list;
+       struct acpi_nfit_data_region bdw[0];
+};
+
+struct nfit_idt {
+       struct list_head list;
+       struct acpi_nfit_interleave idt[0];
+};
+
+struct nfit_flush {
+       struct list_head list;
+       struct acpi_nfit_flush_address flush[0];
+};
+
+struct nfit_memdev {
+       struct list_head list;
+       struct acpi_nfit_memory_map memdev[0];
+};
+
+/* assembled tables for a given dimm/memory-device */
+struct nfit_mem {
+       struct nvdimm *nvdimm;
+       struct acpi_nfit_memory_map *memdev_dcr;
+       struct acpi_nfit_memory_map *memdev_pmem;
+       struct acpi_nfit_memory_map *memdev_bdw;
+       struct acpi_nfit_control_region *dcr;
+       struct acpi_nfit_data_region *bdw;
+       struct acpi_nfit_system_address *spa_dcr;
+       struct acpi_nfit_system_address *spa_bdw;
+       struct acpi_nfit_interleave *idt_dcr;
+       struct acpi_nfit_interleave *idt_bdw;
+       struct nfit_flush *nfit_flush;
+       struct list_head list;
+       struct acpi_device *adev;
+       struct acpi_nfit_desc *acpi_desc;
+       struct resource *flush_wpq;
+       unsigned long dsm_mask;
+       int family;
+};
+
+struct acpi_nfit_desc {
+       struct nvdimm_bus_descriptor nd_desc;
+       struct acpi_table_header acpi_header;
+       struct mutex init_mutex;
+       struct list_head memdevs;
+       struct list_head flushes;
+       struct list_head dimms;
+       struct list_head spas;
+       struct list_head dcrs;
+       struct list_head bdws;
+       struct list_head idts;
+       struct nvdimm_bus *nvdimm_bus;
+       struct device *dev;
+       struct nd_cmd_ars_status *ars_status;
+       size_t ars_status_size;
+       struct work_struct work;
+       struct list_head list;
+       struct kernfs_node *scrub_count_state;
+       unsigned int scrub_count;
+       unsigned int cancel:1;
+       unsigned long dimm_cmd_force_en;
+       unsigned long bus_cmd_force_en;
+       int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa,
+                       void *iobuf, u64 len, int rw);
+};
+
+enum nd_blk_mmio_selector {
+       BDW,
+       DCR,
+};
+
+struct nd_blk_addr {
+       union {
+               void __iomem *base;
+               void *aperture;
+       };
+};
+
+struct nfit_blk {
+       struct nfit_blk_mmio {
+               struct nd_blk_addr addr;
+               u64 size;
+               u64 base_offset;
+               u32 line_size;
+               u32 num_lines;
+               u32 table_size;
+               struct acpi_nfit_interleave *idt;
+               struct acpi_nfit_system_address *spa;
+       } mmio[2];
+       struct nd_region *nd_region;
+       u64 bdw_offset; /* post interleave offset */
+       u64 stat_offset;
+       u64 cmd_offset;
+       u32 dimm_flags;
+};
+
+extern struct list_head acpi_descs;
+extern struct mutex acpi_desc_lock;
+int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc);
+
+#ifdef CONFIG_X86_MCE
+void nfit_mce_register(void);
+void nfit_mce_unregister(void);
+#else
+static inline void nfit_mce_register(void)
+{
+}
+static inline void nfit_mce_unregister(void)
+{
+}
+#endif
+
+int nfit_spa_type(struct acpi_nfit_system_address *spa);
+
+static inline struct acpi_nfit_memory_map *__to_nfit_memdev(
+               struct nfit_mem *nfit_mem)
+{
+       if (nfit_mem->memdev_dcr)
+               return nfit_mem->memdev_dcr;
+       return nfit_mem->memdev_pmem;
+}
+
+static inline struct acpi_nfit_desc *to_acpi_desc(
+               struct nvdimm_bus_descriptor *nd_desc)
+{
+       return container_of(nd_desc, struct acpi_nfit_desc, nd_desc);
+}
+
+const u8 *to_nfit_uuid(enum nfit_uuids id);
+int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *nfit, acpi_size sz);
+void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev);
+#endif /* __NFIT_H__ */
index 51c7db2..29cd966 100644 (file)
@@ -56,6 +56,7 @@ static ssize_t node_read_meminfo(struct device *dev,
 {
        int n;
        int nid = dev->id;
+       struct pglist_data *pgdat = NODE_DATA(nid);
        struct sysinfo i;
 
        si_meminfo_node(&i, nid);
@@ -74,16 +75,16 @@ static ssize_t node_read_meminfo(struct device *dev,
                       nid, K(i.totalram),
                       nid, K(i.freeram),
                       nid, K(i.totalram - i.freeram),
-                      nid, K(node_page_state(nid, NR_ACTIVE_ANON) +
-                               node_page_state(nid, NR_ACTIVE_FILE)),
-                      nid, K(node_page_state(nid, NR_INACTIVE_ANON) +
-                               node_page_state(nid, NR_INACTIVE_FILE)),
-                      nid, K(node_page_state(nid, NR_ACTIVE_ANON)),
-                      nid, K(node_page_state(nid, NR_INACTIVE_ANON)),
-                      nid, K(node_page_state(nid, NR_ACTIVE_FILE)),
-                      nid, K(node_page_state(nid, NR_INACTIVE_FILE)),
-                      nid, K(node_page_state(nid, NR_UNEVICTABLE)),
-                      nid, K(node_page_state(nid, NR_MLOCK)));
+                      nid, K(node_page_state(pgdat, NR_ACTIVE_ANON) +
+                               node_page_state(pgdat, NR_ACTIVE_FILE)),
+                      nid, K(node_page_state(pgdat, NR_INACTIVE_ANON) +
+                               node_page_state(pgdat, NR_INACTIVE_FILE)),
+                      nid, K(node_page_state(pgdat, NR_ACTIVE_ANON)),
+                      nid, K(node_page_state(pgdat, NR_INACTIVE_ANON)),
+                      nid, K(node_page_state(pgdat, NR_ACTIVE_FILE)),
+                      nid, K(node_page_state(pgdat, NR_INACTIVE_FILE)),
+                      nid, K(node_page_state(pgdat, NR_UNEVICTABLE)),
+                      nid, K(sum_zone_node_page_state(nid, NR_MLOCK)));
 
 #ifdef CONFIG_HIGHMEM
        n += sprintf(buf + n,
@@ -117,31 +118,30 @@ static ssize_t node_read_meminfo(struct device *dev,
                       "Node %d ShmemPmdMapped: %8lu kB\n"
 #endif
                        ,
-                      nid, K(node_page_state(nid, NR_FILE_DIRTY)),
-                      nid, K(node_page_state(nid, NR_WRITEBACK)),
-                      nid, K(node_page_state(nid, NR_FILE_PAGES)),
-                      nid, K(node_page_state(nid, NR_FILE_MAPPED)),
-                      nid, K(node_page_state(nid, NR_ANON_PAGES)),
+                      nid, K(node_page_state(pgdat, NR_FILE_DIRTY)),
+                      nid, K(node_page_state(pgdat, NR_WRITEBACK)),
+                      nid, K(node_page_state(pgdat, NR_FILE_PAGES)),
+                      nid, K(node_page_state(pgdat, NR_FILE_MAPPED)),
+                      nid, K(node_page_state(pgdat, NR_ANON_MAPPED)),
                       nid, K(i.sharedram),
-                      nid, node_page_state(nid, NR_KERNEL_STACK) *
-                               THREAD_SIZE / 1024,
-                      nid, K(node_page_state(nid, NR_PAGETABLE)),
-                      nid, K(node_page_state(nid, NR_UNSTABLE_NFS)),
-                      nid, K(node_page_state(nid, NR_BOUNCE)),
-                      nid, K(node_page_state(nid, NR_WRITEBACK_TEMP)),
-                      nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE) +
-                               node_page_state(nid, NR_SLAB_UNRECLAIMABLE)),
-                      nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE)),
+                      nid, sum_zone_node_page_state(nid, NR_KERNEL_STACK_KB),
+                      nid, K(sum_zone_node_page_state(nid, NR_PAGETABLE)),
+                      nid, K(node_page_state(pgdat, NR_UNSTABLE_NFS)),
+                      nid, K(sum_zone_node_page_state(nid, NR_BOUNCE)),
+                      nid, K(node_page_state(pgdat, NR_WRITEBACK_TEMP)),
+                      nid, K(sum_zone_node_page_state(nid, NR_SLAB_RECLAIMABLE) +
+                               sum_zone_node_page_state(nid, NR_SLAB_UNRECLAIMABLE)),
+                      nid, K(sum_zone_node_page_state(nid, NR_SLAB_RECLAIMABLE)),
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-                      nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE)),
-                      nid, K(node_page_state(nid, NR_ANON_THPS) *
+                      nid, K(sum_zone_node_page_state(nid, NR_SLAB_UNRECLAIMABLE)),
+                      nid, K(node_page_state(pgdat, NR_ANON_THPS) *
                                       HPAGE_PMD_NR),
-                      nid, K(node_page_state(nid, NR_SHMEM_THPS) *
+                      nid, K(node_page_state(pgdat, NR_SHMEM_THPS) *
                                       HPAGE_PMD_NR),
-                      nid, K(node_page_state(nid, NR_SHMEM_PMDMAPPED) *
+                      nid, K(node_page_state(pgdat, NR_SHMEM_PMDMAPPED) *
                                       HPAGE_PMD_NR));
 #else
-                      nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE)));
+                      nid, K(sum_zone_node_page_state(nid, NR_SLAB_UNRECLAIMABLE)));
 #endif
        n += hugetlb_report_node_meminfo(nid, buf + n);
        return n;
@@ -160,12 +160,12 @@ static ssize_t node_read_numastat(struct device *dev,
                       "interleave_hit %lu\n"
                       "local_node %lu\n"
                       "other_node %lu\n",
-                      node_page_state(dev->id, NUMA_HIT),
-                      node_page_state(dev->id, NUMA_MISS),
-                      node_page_state(dev->id, NUMA_FOREIGN),
-                      node_page_state(dev->id, NUMA_INTERLEAVE_HIT),
-                      node_page_state(dev->id, NUMA_LOCAL),
-                      node_page_state(dev->id, NUMA_OTHER));
+                      sum_zone_node_page_state(dev->id, NUMA_HIT),
+                      sum_zone_node_page_state(dev->id, NUMA_MISS),
+                      sum_zone_node_page_state(dev->id, NUMA_FOREIGN),
+                      sum_zone_node_page_state(dev->id, NUMA_INTERLEAVE_HIT),
+                      sum_zone_node_page_state(dev->id, NUMA_LOCAL),
+                      sum_zone_node_page_state(dev->id, NUMA_OTHER));
 }
 static DEVICE_ATTR(numastat, S_IRUGO, node_read_numastat, NULL);
 
@@ -173,12 +173,18 @@ static ssize_t node_read_vmstat(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
        int nid = dev->id;
+       struct pglist_data *pgdat = NODE_DATA(nid);
        int i;
        int n = 0;
 
        for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
                n += sprintf(buf+n, "%s %lu\n", vmstat_text[i],
-                            node_page_state(nid, i));
+                            sum_zone_node_page_state(nid, i));
+
+       for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
+               n += sprintf(buf+n, "%s %lu\n",
+                            vmstat_text[i + NR_VM_ZONE_STAT_ITEMS],
+                            node_page_state(pgdat, i));
 
        return n;
 }
index ba5145d..3022dad 100644 (file)
@@ -379,7 +379,7 @@ static int brd_rw_page(struct block_device *bdev, sector_t sector,
 
 #ifdef CONFIG_BLK_DEV_RAM_DAX
 static long brd_direct_access(struct block_device *bdev, sector_t sector,
-                       void __pmem **kaddr, pfn_t *pfn, long size)
+                       void **kaddr, pfn_t *pfn, long size)
 {
        struct brd_device *brd = bdev->bd_disk->private_data;
        struct page *page;
@@ -389,7 +389,7 @@ static long brd_direct_access(struct block_device *bdev, sector_t sector,
        page = brd_insert_page(brd, sector);
        if (!page)
                return -ENOSPC;
-       *kaddr = (void __pmem *)page_address(page);
+       *kaddr = page_address(page);
        *pfn = page_to_pfn_t(page);
 
        return PAGE_SIZE;
index be91a8d..de5c3ee 100644 (file)
@@ -425,9 +425,6 @@ static int drbd_single_open(struct file *file, int (*show)(struct seq_file *, vo
        /* Are we still linked,
         * or has debugfs_remove() already been called? */
        parent = file->f_path.dentry->d_parent;
-       /* not sure if this can happen: */
-       if (!parent || d_really_is_negative(parent))
-               goto out;
        /* serialize with d_delete() */
        inode_lock(d_inode(parent));
        /* Make sure the object is still alive */
@@ -440,7 +437,6 @@ static int drbd_single_open(struct file *file, int (*show)(struct seq_file *, vo
                if (ret)
                        kref_put(kref, release);
        }
-out:
        return ret;
 }
 
index 8d0af74..7f06224 100644 (file)
@@ -1668,13 +1668,12 @@ static int rand_initialize(void)
 #ifdef CONFIG_NUMA
        pool = kmalloc(num_nodes * sizeof(void *),
                       GFP_KERNEL|__GFP_NOFAIL|__GFP_ZERO);
-       for (i=0; i < num_nodes; i++) {
+       for_each_online_node(i) {
                crng = kmalloc_node(sizeof(struct crng_state),
                                    GFP_KERNEL | __GFP_NOFAIL, i);
                spin_lock_init(&crng->lock);
                crng_initialize(crng);
                pool[i] = crng;
-
        }
        mb();
        crng_node_pool = pool;
index b891a12..803f395 100644 (file)
@@ -211,11 +211,9 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res,
        }
        dax_dev->dev = dev;
 
-       rc = devm_add_action(dax_region->dev, unregister_dax_dev, dev);
-       if (rc) {
-               unregister_dax_dev(dev);
+       rc = devm_add_action_or_reset(dax_region->dev, unregister_dax_dev, dev);
+       if (rc)
                return rc;
-       }
 
        return 0;
 
index 55d510e..dfb1685 100644 (file)
@@ -102,21 +102,19 @@ static int dax_pmem_probe(struct device *dev)
        if (rc)
                return rc;
 
-       rc = devm_add_action(dev, dax_pmem_percpu_exit, &dax_pmem->ref);
-       if (rc) {
-               dax_pmem_percpu_exit(&dax_pmem->ref);
+       rc = devm_add_action_or_reset(dev, dax_pmem_percpu_exit,
+                                                       &dax_pmem->ref);
+       if (rc)
                return rc;
-       }
 
        addr = devm_memremap_pages(dev, &res, &dax_pmem->ref, altmap);
        if (IS_ERR(addr))
                return PTR_ERR(addr);
 
-       rc = devm_add_action(dev, dax_pmem_percpu_kill, &dax_pmem->ref);
-       if (rc) {
-               dax_pmem_percpu_kill(&dax_pmem->ref);
+       rc = devm_add_action_or_reset(dev, dax_pmem_percpu_kill,
+                                                       &dax_pmem->ref);
+       if (rc)
                return rc;
-       }
 
        nd_region = to_nd_region(dev->parent);
        dax_region = alloc_dax_region(dev, nd_region->id, &res,
index 8c98779..739f797 100644 (file)
@@ -339,6 +339,20 @@ config MV_XOR
        ---help---
          Enable support for the Marvell XOR engine.
 
+config MV_XOR_V2
+       bool "Marvell XOR engine version 2 support "
+       depends on ARM64
+       select DMA_ENGINE
+       select DMA_ENGINE_RAID
+       select ASYNC_TX_ENABLE_CHANNEL_SWITCH
+       select GENERIC_MSI_IRQ_DOMAIN
+       ---help---
+         Enable support for the Marvell version 2 XOR engine.
+
+         This engine provides acceleration for copy, XOR and RAID6
+         operations, and is available on Marvell Armada 7K and 8K
+         platforms.
+
 config MXS_DMA
        bool "MXS DMA support"
        depends on SOC_IMX23 || SOC_IMX28 || SOC_IMX6Q || SOC_IMX6UL
@@ -519,19 +533,31 @@ config XGENE_DMA
        help
          Enable support for the APM X-Gene SoC DMA engine.
 
-config XILINX_VDMA
-       tristate "Xilinx AXI VDMA Engine"
+config XILINX_DMA
+       tristate "Xilinx AXI DMAS Engine"
        depends on (ARCH_ZYNQ || MICROBLAZE || ARM64)
        select DMA_ENGINE
        help
          Enable support for Xilinx AXI VDMA Soft IP.
 
-         This engine provides high-bandwidth direct memory access
+         AXI VDMA engine provides high-bandwidth direct memory access
          between memory and AXI4-Stream video type target
          peripherals including peripherals which support AXI4-
          Stream Video Protocol.  It has two stream interfaces/
          channels, Memory Mapped to Stream (MM2S) and Stream to
          Memory Mapped (S2MM) for the data transfers.
+         AXI CDMA engine provides high-bandwidth direct memory access
+         between a memory-mapped source address and a memory-mapped
+         destination address.
+         AXI DMA engine provides high-bandwidth one dimensional direct
+         memory access between memory and AXI4-Stream target peripherals.
+
+config XILINX_ZYNQMP_DMA
+       tristate "Xilinx ZynqMP DMA Engine"
+       depends on (ARCH_ZYNQ || MICROBLAZE || ARM64)
+       select DMA_ENGINE
+       help
+         Enable support for Xilinx ZynqMP DMA controller.
 
 config ZX_DMA
        tristate "ZTE ZX296702 DMA support"
index 614f28b..e4dc9ca 100644 (file)
@@ -45,6 +45,7 @@ obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o
 obj-$(CONFIG_MOXART_DMA) += moxart-dma.o
 obj-$(CONFIG_MPC512X_DMA) += mpc512x_dma.o
 obj-$(CONFIG_MV_XOR) += mv_xor.o
+obj-$(CONFIG_MV_XOR_V2) += mv_xor_v2.o
 obj-$(CONFIG_MXS_DMA) += mxs-dma.o
 obj-$(CONFIG_MX3_IPU) += ipu/
 obj-$(CONFIG_NBPFAXI_DMA) += nbpfaxi.o
index 81db1c4..939a7c3 100644 (file)
@@ -1443,8 +1443,6 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
        dsg = kzalloc(sizeof(struct pl08x_sg), GFP_NOWAIT);
        if (!dsg) {
                pl08x_free_txd(pl08x, txd);
-               dev_err(&pl08x->adev->dev, "%s no memory for pl080 sg\n",
-                               __func__);
                return NULL;
        }
        list_add_tail(&dsg->node, &txd->dsg_list);
@@ -1901,11 +1899,8 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
         */
        for (i = 0; i < channels; i++) {
                chan = kzalloc(sizeof(*chan), GFP_KERNEL);
-               if (!chan) {
-                       dev_err(&pl08x->adev->dev,
-                               "%s no memory for channel\n", __func__);
+               if (!chan)
                        return -ENOMEM;
-               }
 
                chan->host = pl08x;
                chan->state = PL08X_CHAN_IDLE;
@@ -2360,9 +2355,6 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
        pl08x->phy_chans = kzalloc((vd->channels * sizeof(*pl08x->phy_chans)),
                        GFP_KERNEL);
        if (!pl08x->phy_chans) {
-               dev_err(&adev->dev, "%s failed to allocate "
-                       "physical channel holders\n",
-                       __func__);
                ret = -ENOMEM;
                goto out_no_phychans;
        }
index 75bd662..e434ffe 100644 (file)
@@ -456,7 +456,7 @@ static struct at_xdmac_desc *at_xdmac_alloc_desc(struct dma_chan *chan,
        return desc;
 }
 
-void at_xdmac_init_used_desc(struct at_xdmac_desc *desc)
+static void at_xdmac_init_used_desc(struct at_xdmac_desc *desc)
 {
        memset(&desc->lld, 0, sizeof(desc->lld));
        INIT_LIST_HEAD(&desc->descs_list);
@@ -1195,14 +1195,14 @@ static struct at_xdmac_desc *at_xdmac_memset_create_desc(struct dma_chan *chan,
        desc->lld.mbr_cfg = chan_cc;
 
        dev_dbg(chan2dev(chan),
-               "%s: lld: mbr_da=%pad, mbr_ds=%pad, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n",
-               __func__, &desc->lld.mbr_da, &desc->lld.mbr_ds, desc->lld.mbr_ubc,
+               "%s: lld: mbr_da=%pad, mbr_ds=0x%08x, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n",
+               __func__, &desc->lld.mbr_da, desc->lld.mbr_ds, desc->lld.mbr_ubc,
                desc->lld.mbr_cfg);
 
        return desc;
 }
 
-struct dma_async_tx_descriptor *
+static struct dma_async_tx_descriptor *
 at_xdmac_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value,
                         size_t len, unsigned long flags)
 {
index 6149b27..e18dc59 100644 (file)
@@ -393,11 +393,12 @@ static void bcm2835_dma_fill_cb_chain_with_sg(
        unsigned int sg_len)
 {
        struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
-       size_t max_len = bcm2835_dma_max_frame_length(c);
-       unsigned int i, len;
+       size_t len, max_len;
+       unsigned int i;
        dma_addr_t addr;
        struct scatterlist *sgent;
 
+       max_len = bcm2835_dma_max_frame_length(c);
        for_each_sg(sgl, sgent, sg_len, i) {
                for (addr = sg_dma_address(sgent), len = sg_dma_len(sgent);
                     len > 0;
@@ -613,7 +614,7 @@ static void bcm2835_dma_issue_pending(struct dma_chan *chan)
        spin_unlock_irqrestore(&c->vc.lock, flags);
 }
 
-struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_memcpy(
+static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_memcpy(
        struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
        size_t len, unsigned long flags)
 {
index 180fedb..7ce8437 100644 (file)
@@ -397,8 +397,6 @@ static int mpc52xx_bcom_probe(struct platform_device *op)
        /* Get a clean struct */
        bcom_eng = kzalloc(sizeof(struct bcom_engine), GFP_KERNEL);
        if (!bcom_eng) {
-               printk(KERN_ERR DRIVER_NAME ": "
-                       "Can't allocate state structure\n");
                rv = -ENOMEM;
                goto error_sramclean;
        }
index c340ca9..e4acd63 100644 (file)
@@ -266,7 +266,7 @@ static int dma_memcpy_channels[] = {
                        COH901318_CX_CTRL_DDMA_LEGACY | \
                        COH901318_CX_CTRL_PRDD_SOURCE)
 
-const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = {
+static const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = {
        {
                .number = U300_DMA_MSL_TX_0,
                .name = "MSL TX 0",
@@ -1280,6 +1280,7 @@ struct coh901318_desc {
 struct coh901318_base {
        struct device *dev;
        void __iomem *virtbase;
+       unsigned int irq;
        struct coh901318_pool pool;
        struct powersave pm;
        struct dma_device dma_slave;
@@ -1364,7 +1365,6 @@ static int coh901318_debugfs_read(struct file *file, char __user *buf,
 }
 
 static const struct file_operations coh901318_debugfs_status_operations = {
-       .owner          = THIS_MODULE,
        .open           = simple_open,
        .read           = coh901318_debugfs_read,
        .llseek         = default_llseek,
@@ -2422,7 +2422,7 @@ coh901318_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
        enum dma_status ret;
 
        ret = dma_cookie_status(chan, cookie, txstate);
-       if (ret == DMA_COMPLETE)
+       if (ret == DMA_COMPLETE || !txstate)
                return ret;
 
        dma_set_residue(txstate, coh901318_get_bytes_left(chan));
@@ -2680,6 +2680,8 @@ static int __init coh901318_probe(struct platform_device *pdev)
        if (err)
                return err;
 
+       base->irq = irq;
+
        err = coh901318_pool_create(&base->pool, &pdev->dev,
                                    sizeof(struct coh901318_lli),
                                    32);
@@ -2755,11 +2757,31 @@ static int __init coh901318_probe(struct platform_device *pdev)
        coh901318_pool_destroy(&base->pool);
        return err;
 }
+static void coh901318_base_remove(struct coh901318_base *base, const int *pick_chans)
+{
+       int chans_i;
+       int i = 0;
+       struct coh901318_chan *cohc;
+
+       for (chans_i = 0; pick_chans[chans_i] != -1; chans_i += 2) {
+               for (i = pick_chans[chans_i]; i <= pick_chans[chans_i+1]; i++) {
+                       cohc = &base->chans[i];
+
+                       tasklet_kill(&cohc->tasklet);
+               }
+       }
+
+}
 
 static int coh901318_remove(struct platform_device *pdev)
 {
        struct coh901318_base *base = platform_get_drvdata(pdev);
 
+       devm_free_irq(&pdev->dev, base->irq, base);
+
+       coh901318_base_remove(base, dma_slave_channels);
+       coh901318_base_remove(base, dma_memcpy_channels);
+
        of_dma_controller_free(pdev->dev.of_node);
        dma_async_device_unregister(&base->dma_memcpy);
        dma_async_device_unregister(&base->dma_slave);
@@ -2780,13 +2802,13 @@ static struct platform_driver coh901318_driver = {
        },
 };
 
-int __init coh901318_init(void)
+static int __init coh901318_init(void)
 {
        return platform_driver_probe(&coh901318_driver, coh901318_probe);
 }
 subsys_initcall(coh901318_init);
 
-void __exit coh901318_exit(void)
+static void __exit coh901318_exit(void)
 {
        platform_driver_unregister(&coh901318_driver);
 }
index ceedafb..4b23174 100644 (file)
@@ -497,16 +497,13 @@ static struct dma_async_tx_descriptor *cppi41_dma_prep_slave_sg(
        struct cppi41_desc *d;
        struct scatterlist *sg;
        unsigned int i;
-       unsigned int num;
 
-       num = 0;
        d = c->desc;
        for_each_sg(sgl, sg, sg_len, i) {
                u32 addr;
                u32 len;
 
                /* We need to use more than one desc once musb supports sg */
-               BUG_ON(num > 0);
                addr = lower_32_bits(sg_dma_address(sg));
                len = sg_dma_len(sg);
 
index c346809..7f0b9aa 100644 (file)
@@ -270,6 +270,9 @@ static irqreturn_t axi_dmac_interrupt_handler(int irq, void *devid)
        unsigned int pending;
 
        pending = axi_dmac_read(dmac, AXI_DMAC_REG_IRQ_PENDING);
+       if (!pending)
+               return IRQ_NONE;
+
        axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_PENDING, pending);
 
        spin_lock(&dmac->chan.vchan.lock);
@@ -579,7 +582,9 @@ static int axi_dmac_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        dmac->irq = platform_get_irq(pdev, 0);
-       if (dmac->irq <= 0)
+       if (dmac->irq < 0)
+               return dmac->irq;
+       if (dmac->irq == 0)
                return -EINVAL;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -683,6 +688,7 @@ static const struct of_device_id axi_dmac_of_match_table[] = {
        { .compatible = "adi,axi-dmac-1.00.a" },
        { },
 };
+MODULE_DEVICE_TABLE(of, axi_dmac_of_match_table);
 
 static struct platform_driver axi_dmac_driver = {
        .driver = {
index 7638b24..9689b36 100644 (file)
@@ -573,12 +573,26 @@ err_unregister:
        return ret;
 }
 
+static void jz4740_cleanup_vchan(struct dma_device *dmadev)
+{
+       struct jz4740_dmaengine_chan *chan, *_chan;
+
+       list_for_each_entry_safe(chan, _chan,
+                               &dmadev->channels, vchan.chan.device_node) {
+               list_del(&chan->vchan.chan.device_node);
+               tasklet_kill(&chan->vchan.task);
+       }
+}
+
+
 static int jz4740_dma_remove(struct platform_device *pdev)
 {
        struct jz4740_dma_dev *dmadev = platform_get_drvdata(pdev);
        int irq = platform_get_irq(pdev, 0);
 
        free_irq(irq, dmadev);
+
+       jz4740_cleanup_vchan(&dmadev->ddev);
        dma_async_device_unregister(&dmadev->ddev);
        clk_disable_unprepare(dmadev->clk);
 
index b8576fd..1245db5 100644 (file)
@@ -51,6 +51,16 @@ module_param(iterations, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(iterations,
                "Iterations before stopping test (default: infinite)");
 
+static unsigned int sg_buffers = 1;
+module_param(sg_buffers, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(sg_buffers,
+               "Number of scatter gather buffers (default: 1)");
+
+static unsigned int dmatest = 1;
+module_param(dmatest, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dmatest,
+               "dmatest 0-memcpy 1-slave_sg (default: 1)");
+
 static unsigned int xor_sources = 3;
 module_param(xor_sources, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(xor_sources,
@@ -431,6 +441,8 @@ static int dmatest_func(void *data)
        dev = chan->device;
        if (thread->type == DMA_MEMCPY)
                src_cnt = dst_cnt = 1;
+       else if (thread->type == DMA_SG)
+               src_cnt = dst_cnt = sg_buffers;
        else if (thread->type == DMA_XOR) {
                /* force odd to ensure dst = src */
                src_cnt = min_odd(params->xor_sources | 1, dev->max_xor);
@@ -485,6 +497,8 @@ static int dmatest_func(void *data)
                dma_addr_t *dsts;
                unsigned int src_off, dst_off, len;
                u8 align = 0;
+               struct scatterlist tx_sg[src_cnt];
+               struct scatterlist rx_sg[src_cnt];
 
                total_tests++;
 
@@ -577,10 +591,22 @@ static int dmatest_func(void *data)
                        um->bidi_cnt++;
                }
 
+               sg_init_table(tx_sg, src_cnt);
+               sg_init_table(rx_sg, src_cnt);
+               for (i = 0; i < src_cnt; i++) {
+                       sg_dma_address(&rx_sg[i]) = srcs[i];
+                       sg_dma_address(&tx_sg[i]) = dsts[i] + dst_off;
+                       sg_dma_len(&tx_sg[i]) = len;
+                       sg_dma_len(&rx_sg[i]) = len;
+               }
+
                if (thread->type == DMA_MEMCPY)
                        tx = dev->device_prep_dma_memcpy(chan,
                                                         dsts[0] + dst_off,
                                                         srcs[0], len, flags);
+               else if (thread->type == DMA_SG)
+                       tx = dev->device_prep_dma_sg(chan, tx_sg, src_cnt,
+                                                    rx_sg, src_cnt, flags);
                else if (thread->type == DMA_XOR)
                        tx = dev->device_prep_dma_xor(chan,
                                                      dsts[0] + dst_off,
@@ -748,6 +774,8 @@ static int dmatest_add_threads(struct dmatest_info *info,
 
        if (type == DMA_MEMCPY)
                op = "copy";
+       else if (type == DMA_SG)
+               op = "sg";
        else if (type == DMA_XOR)
                op = "xor";
        else if (type == DMA_PQ)
@@ -802,9 +830,19 @@ static int dmatest_add_channel(struct dmatest_info *info,
        INIT_LIST_HEAD(&dtc->threads);
 
        if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) {
-               cnt = dmatest_add_threads(info, dtc, DMA_MEMCPY);
-               thread_count += cnt > 0 ? cnt : 0;
+               if (dmatest == 0) {
+                       cnt = dmatest_add_threads(info, dtc, DMA_MEMCPY);
+                       thread_count += cnt > 0 ? cnt : 0;
+               }
        }
+
+       if (dma_has_cap(DMA_SG, dma_dev->cap_mask)) {
+               if (dmatest == 1) {
+                       cnt = dmatest_add_threads(info, dtc, DMA_SG);
+                       thread_count += cnt > 0 ? cnt : 0;
+               }
+       }
+
        if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
                cnt = dmatest_add_threads(info, dtc, DMA_XOR);
                thread_count += cnt > 0 ? cnt : 0;
@@ -877,6 +915,7 @@ static void run_threaded_test(struct dmatest_info *info)
 
        request_channels(info, DMA_MEMCPY);
        request_channels(info, DMA_XOR);
+       request_channels(info, DMA_SG);
        request_channels(info, DMA_PQ);
 }
 
index 8181ed1..3d277fa 100644 (file)
@@ -239,6 +239,9 @@ struct edma_cc {
        bool                            chmap_exist;
        enum dma_event_q                default_queue;
 
+       unsigned int                    ccint;
+       unsigned int                    ccerrint;
+
        /*
         * The slot_inuse bit for each PaRAM slot is clear unless the slot is
         * in use by Linux or if it is allocated to be used by DSP.
@@ -1069,10 +1072,8 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
 
        edesc = kzalloc(sizeof(*edesc) + sg_len * sizeof(edesc->pset[0]),
                        GFP_ATOMIC);
-       if (!edesc) {
-               dev_err(dev, "%s: Failed to allocate a descriptor\n", __func__);
+       if (!edesc)
                return NULL;
-       }
 
        edesc->pset_nr = sg_len;
        edesc->residue = 0;
@@ -1114,14 +1115,17 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
                edesc->absync = ret;
                edesc->residue += sg_dma_len(sg);
 
-               /* If this is the last in a current SG set of transactions,
-                  enable interrupts so that next set is processed */
-               if (!((i+1) % MAX_NR_SG))
-                       edesc->pset[i].param.opt |= TCINTEN;
-
-               /* If this is the last set, enable completion interrupt flag */
                if (i == sg_len - 1)
+                       /* Enable completion interrupt */
                        edesc->pset[i].param.opt |= TCINTEN;
+               else if (!((i+1) % MAX_NR_SG))
+                       /*
+                        * Enable early completion interrupt for the
+                        * intermediateset. In this case the driver will be
+                        * notified when the paRAM set is submitted to TC. This
+                        * will allow more time to set up the next set of slots.
+                        */
+                       edesc->pset[i].param.opt |= (TCINTEN | TCCMODE);
        }
        edesc->residue_stat = edesc->residue;
 
@@ -1173,10 +1177,8 @@ static struct dma_async_tx_descriptor *edma_prep_dma_memcpy(
 
        edesc = kzalloc(sizeof(*edesc) + nslots * sizeof(edesc->pset[0]),
                        GFP_ATOMIC);
-       if (!edesc) {
-               dev_dbg(dev, "Failed to allocate a descriptor\n");
+       if (!edesc)
                return NULL;
-       }
 
        edesc->pset_nr = nslots;
        edesc->residue = edesc->residue_stat = len;
@@ -1298,10 +1300,8 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
 
        edesc = kzalloc(sizeof(*edesc) + nslots * sizeof(edesc->pset[0]),
                        GFP_ATOMIC);
-       if (!edesc) {
-               dev_err(dev, "%s: Failed to allocate a descriptor\n", __func__);
+       if (!edesc)
                return NULL;
-       }
 
        edesc->cyclic = 1;
        edesc->pset_nr = nslots;
@@ -2207,10 +2207,8 @@ static int edma_probe(struct platform_device *pdev)
                return ret;
 
        ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
-       if (!ecc) {
-               dev_err(dev, "Can't allocate controller\n");
+       if (!ecc)
                return -ENOMEM;
-       }
 
        ecc->dev = dev;
        ecc->id = pdev->id;
@@ -2288,6 +2286,7 @@ static int edma_probe(struct platform_device *pdev)
                        dev_err(dev, "CCINT (%d) failed --> %d\n", irq, ret);
                        return ret;
                }
+               ecc->ccint = irq;
        }
 
        irq = platform_get_irq_byname(pdev, "edma3_ccerrint");
@@ -2303,6 +2302,7 @@ static int edma_probe(struct platform_device *pdev)
                        dev_err(dev, "CCERRINT (%d) failed --> %d\n", irq, ret);
                        return ret;
                }
+               ecc->ccerrint = irq;
        }
 
        ecc->dummy_slot = edma_alloc_slot(ecc, EDMA_SLOT_ANY);
@@ -2393,11 +2393,27 @@ err_reg1:
        return ret;
 }
 
+static void edma_cleanupp_vchan(struct dma_device *dmadev)
+{
+       struct edma_chan *echan, *_echan;
+
+       list_for_each_entry_safe(echan, _echan,
+                       &dmadev->channels, vchan.chan.device_node) {
+               list_del(&echan->vchan.chan.device_node);
+               tasklet_kill(&echan->vchan.task);
+       }
+}
+
 static int edma_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct edma_cc *ecc = dev_get_drvdata(dev);
 
+       devm_free_irq(dev, ecc->ccint, ecc);
+       devm_free_irq(dev, ecc->ccerrint, ecc);
+
+       edma_cleanupp_vchan(&ecc->dma_slave);
+
        if (dev->of_node)
                of_dma_controller_free(dev->of_node);
        dma_async_device_unregister(&ecc->dma_slave);
index be2e62b..6775f2c 100644 (file)
@@ -852,6 +852,25 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma
        return 0;
 }
 
+static void fsl_edma_irq_exit(
+               struct platform_device *pdev, struct fsl_edma_engine *fsl_edma)
+{
+       if (fsl_edma->txirq == fsl_edma->errirq) {
+               devm_free_irq(&pdev->dev, fsl_edma->txirq, fsl_edma);
+       } else {
+               devm_free_irq(&pdev->dev, fsl_edma->txirq, fsl_edma);
+               devm_free_irq(&pdev->dev, fsl_edma->errirq, fsl_edma);
+       }
+}
+
+static void fsl_disable_clocks(struct fsl_edma_engine *fsl_edma)
+{
+       int i;
+
+       for (i = 0; i < DMAMUX_NR; i++)
+               clk_disable_unprepare(fsl_edma->muxclk[i]);
+}
+
 static int fsl_edma_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -897,6 +916,10 @@ static int fsl_edma_probe(struct platform_device *pdev)
 
                ret = clk_prepare_enable(fsl_edma->muxclk[i]);
                if (ret) {
+                       /* disable only clks which were enabled on error */
+                       for (; i >= 0; i--)
+                               clk_disable_unprepare(fsl_edma->muxclk[i]);
+
                        dev_err(&pdev->dev, "DMAMUX clk block failed.\n");
                        return ret;
                }
@@ -951,14 +974,18 @@ static int fsl_edma_probe(struct platform_device *pdev)
 
        ret = dma_async_device_register(&fsl_edma->dma_dev);
        if (ret) {
-               dev_err(&pdev->dev, "Can't register Freescale eDMA engine.\n");
+               dev_err(&pdev->dev,
+                       "Can't register Freescale eDMA engine. (%d)\n", ret);
+               fsl_disable_clocks(fsl_edma);
                return ret;
        }
 
        ret = of_dma_controller_register(np, fsl_edma_xlate, fsl_edma);
        if (ret) {
-               dev_err(&pdev->dev, "Can't register Freescale eDMA of_dma.\n");
+               dev_err(&pdev->dev,
+                       "Can't register Freescale eDMA of_dma. (%d)\n", ret);
                dma_async_device_unregister(&fsl_edma->dma_dev);
+               fsl_disable_clocks(fsl_edma);
                return ret;
        }
 
@@ -968,17 +995,27 @@ static int fsl_edma_probe(struct platform_device *pdev)
        return 0;
 }
 
+static void fsl_edma_cleanup_vchan(struct dma_device *dmadev)
+{
+       struct fsl_edma_chan *chan, *_chan;
+
+       list_for_each_entry_safe(chan, _chan,
+                               &dmadev->channels, vchan.chan.device_node) {
+               list_del(&chan->vchan.chan.device_node);
+               tasklet_kill(&chan->vchan.task);
+       }
+}
+
 static int fsl_edma_remove(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct fsl_edma_engine *fsl_edma = platform_get_drvdata(pdev);
-       int i;
 
+       fsl_edma_irq_exit(pdev, fsl_edma);
+       fsl_edma_cleanup_vchan(&fsl_edma->dma_dev);
        of_dma_controller_free(np);
        dma_async_device_unregister(&fsl_edma->dma_dev);
-
-       for (i = 0; i < DMAMUX_NR; i++)
-               clk_disable_unprepare(fsl_edma->muxclk[i]);
+       fsl_disable_clocks(fsl_edma);
 
        return 0;
 }
index 4d9470f..aad167e 100644 (file)
@@ -337,7 +337,7 @@ static struct dma_async_tx_descriptor *fsl_re_prep_dma_genq(
 
        re_chan = container_of(chan, struct fsl_re_chan, chan);
        if (len > FSL_RE_MAX_DATA_LEN) {
-               dev_err(re_chan->dev, "genq tx length %lu, max length %d\n",
+               dev_err(re_chan->dev, "genq tx length %zu, max length %d\n",
                        len, FSL_RE_MAX_DATA_LEN);
                return NULL;
        }
@@ -424,7 +424,7 @@ static struct dma_async_tx_descriptor *fsl_re_prep_dma_pq(
 
        re_chan = container_of(chan, struct fsl_re_chan, chan);
        if (len > FSL_RE_MAX_DATA_LEN) {
-               dev_err(re_chan->dev, "pq tx length is %lu, max length is %d\n",
+               dev_err(re_chan->dev, "pq tx length is %zu, max length is %d\n",
                        len, FSL_RE_MAX_DATA_LEN);
                return NULL;
        }
@@ -545,7 +545,7 @@ static struct dma_async_tx_descriptor *fsl_re_prep_dma_memcpy(
        re_chan = container_of(chan, struct fsl_re_chan, chan);
 
        if (len > FSL_RE_MAX_DATA_LEN) {
-               dev_err(re_chan->dev, "cp tx length is %lu, max length is %d\n",
+               dev_err(re_chan->dev, "cp tx length is %zu, max length is %d\n",
                        len, FSL_RE_MAX_DATA_LEN);
                return NULL;
        }
@@ -856,6 +856,8 @@ static int fsl_re_probe(struct platform_device *ofdev)
 
 static void fsl_re_remove_chan(struct fsl_re_chan *chan)
 {
+       tasklet_kill(&chan->irqtask);
+
        dma_pool_free(chan->re_dev->hw_desc_pool, chan->inb_ring_virt_addr,
                      chan->inb_phys_addr);
 
@@ -890,7 +892,6 @@ static struct of_device_id fsl_re_ids[] = {
 static struct platform_driver fsl_re_driver = {
        .driver = {
                .name = "fsl-raideng",
-               .owner = THIS_MODULE,
                .of_match_table = fsl_re_ids,
        },
        .probe = fsl_re_probe,
index a8828ed..911b717 100644 (file)
@@ -1234,7 +1234,6 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
        /* alloc channel */
        chan = kzalloc(sizeof(*chan), GFP_KERNEL);
        if (!chan) {
-               dev_err(fdev->dev, "no free memory for DMA channels!\n");
                err = -ENOMEM;
                goto out_return;
        }
@@ -1340,7 +1339,6 @@ static int fsldma_of_probe(struct platform_device *op)
 
        fdev = kzalloc(sizeof(*fdev), GFP_KERNEL);
        if (!fdev) {
-               dev_err(&op->dev, "No enough memory for 'priv'\n");
                err = -ENOMEM;
                goto out_return;
        }
index 48d85f8..a960608 100644 (file)
@@ -167,6 +167,7 @@ struct imxdma_channel {
        u32                             ccr_to_device;
        bool                            enabled_2d;
        int                             slot_2d;
+       unsigned int                    irq;
 };
 
 enum imx_dma_type {
@@ -186,6 +187,9 @@ struct imxdma_engine {
        struct imx_dma_2d_config        slots_2d[IMX_DMA_2D_SLOTS];
        struct imxdma_channel           channel[IMX_DMA_CHANNELS];
        enum imx_dma_type               devtype;
+       unsigned int                    irq;
+       unsigned int                    irq_err;
+
 };
 
 struct imxdma_filter_data {
@@ -1048,7 +1052,7 @@ static struct dma_chan *imxdma_xlate(struct of_phandle_args *dma_spec,
 }
 
 static int __init imxdma_probe(struct platform_device *pdev)
-       {
+{
        struct imxdma_engine *imxdma;
        struct resource *res;
        const struct of_device_id *of_id;
@@ -1100,6 +1104,7 @@ static int __init imxdma_probe(struct platform_device *pdev)
                        dev_warn(imxdma->dev, "Can't register IRQ for DMA\n");
                        goto disable_dma_ahb_clk;
                }
+               imxdma->irq = irq;
 
                irq_err = platform_get_irq(pdev, 1);
                if (irq_err < 0) {
@@ -1113,6 +1118,7 @@ static int __init imxdma_probe(struct platform_device *pdev)
                        dev_warn(imxdma->dev, "Can't register ERRIRQ for DMA\n");
                        goto disable_dma_ahb_clk;
                }
+               imxdma->irq_err = irq_err;
        }
 
        /* enable DMA module */
@@ -1150,6 +1156,8 @@ static int __init imxdma_probe(struct platform_device *pdev)
                                         irq + i, i);
                                goto disable_dma_ahb_clk;
                        }
+
+                       imxdmac->irq = irq + i;
                        init_timer(&imxdmac->watchdog);
                        imxdmac->watchdog.function = &imxdma_watchdog;
                        imxdmac->watchdog.data = (unsigned long)imxdmac;
@@ -1217,10 +1225,31 @@ disable_dma_ipg_clk:
        return ret;
 }
 
+static void imxdma_free_irq(struct platform_device *pdev, struct imxdma_engine *imxdma)
+{
+       int i;
+
+       if (is_imx1_dma(imxdma)) {
+               disable_irq(imxdma->irq);
+               disable_irq(imxdma->irq_err);
+       }
+
+       for (i = 0; i < IMX_DMA_CHANNELS; i++) {
+               struct imxdma_channel *imxdmac = &imxdma->channel[i];
+
+               if (!is_imx1_dma(imxdma))
+                       disable_irq(imxdmac->irq);
+
+               tasklet_kill(&imxdmac->dma_tasklet);
+       }
+}
+
 static int imxdma_remove(struct platform_device *pdev)
 {
        struct imxdma_engine *imxdma = platform_get_drvdata(pdev);
 
+       imxdma_free_irq(pdev, imxdma);
+
         dma_async_device_unregister(&imxdma->dma_device);
 
        if (pdev->dev.of_node)
index 0f6fd42..03ec76f 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/bitops.h>
@@ -385,6 +386,7 @@ struct sdma_engine {
        const struct sdma_driver_data   *drvdata;
        u32                             spba_start_addr;
        u32                             spba_end_addr;
+       unsigned int                    irq;
 };
 
 static struct sdma_driver_data sdma_imx31 = {
@@ -571,28 +573,20 @@ static void sdma_enable_channel(struct sdma_engine *sdma, int channel)
 static int sdma_run_channel0(struct sdma_engine *sdma)
 {
        int ret;
-       unsigned long timeout = 500;
+       u32 reg;
 
        sdma_enable_channel(sdma, 0);
 
-       while (!(ret = readl_relaxed(sdma->regs + SDMA_H_INTR) & 1)) {
-               if (timeout-- <= 0)
-                       break;
-               udelay(1);
-       }
-
-       if (ret) {
-               /* Clear the interrupt status */
-               writel_relaxed(ret, sdma->regs + SDMA_H_INTR);
-       } else {
+       ret = readl_relaxed_poll_timeout_atomic(sdma->regs + SDMA_H_STATSTOP,
+                                               reg, !(reg & 1), 1, 500);
+       if (ret)
                dev_err(sdma->dev, "Timeout waiting for CH0 ready\n");
-       }
 
        /* Set bits of CONFIG register with dynamic context switching */
        if (readl(sdma->regs + SDMA_H_CONFIG) == 0)
                writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
 
-       return ret ? 0 : -ETIMEDOUT;
+       return ret;
 }
 
 static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
@@ -727,9 +721,9 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id)
        unsigned long stat;
 
        stat = readl_relaxed(sdma->regs + SDMA_H_INTR);
-       /* not interested in channel 0 interrupts */
-       stat &= ~1;
        writel_relaxed(stat, sdma->regs + SDMA_H_INTR);
+       /* channel 0 is special and not handled here, see run_channel0() */
+       stat &= ~1;
 
        while (stat) {
                int channel = fls(stat) - 1;
@@ -758,7 +752,7 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
         * These are needed once we start to support transfers between
         * two peripherals or memory-to-memory transfers
         */
-       int per_2_per = 0, emi_2_emi = 0;
+       int per_2_per = 0;
 
        sdmac->pc_from_device = 0;
        sdmac->pc_to_device = 0;
@@ -766,7 +760,6 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
 
        switch (peripheral_type) {
        case IMX_DMATYPE_MEMORY:
-               emi_2_emi = sdma->script_addrs->ap_2_ap_addr;
                break;
        case IMX_DMATYPE_DSP:
                emi_2_per = sdma->script_addrs->bp_2_ap_addr;
@@ -999,8 +992,6 @@ static int sdma_config_channel(struct dma_chan *chan)
                } else
                        __set_bit(sdmac->event_id0, sdmac->event_mask);
 
-               /* Watermark Level */
-               sdmac->watermark_level |= sdmac->watermark_level;
                /* Address */
                sdmac->shp_addr = sdmac->per_address;
                sdmac->per_addr = sdmac->per_address2;
@@ -1715,6 +1706,8 @@ static int sdma_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       sdma->irq = irq;
+
        sdma->script_addrs = kzalloc(sizeof(*sdma->script_addrs), GFP_KERNEL);
        if (!sdma->script_addrs)
                return -ENOMEM;
@@ -1840,6 +1833,7 @@ static int sdma_remove(struct platform_device *pdev)
        struct sdma_engine *sdma = platform_get_drvdata(pdev);
        int i;
 
+       devm_free_irq(&pdev->dev, sdma->irq, sdma);
        dma_async_device_unregister(&sdma->dma_device);
        kfree(sdma->script_addrs);
        /* Kill the tasklet */
index d406056..7145f77 100644 (file)
@@ -1212,7 +1212,7 @@ static void ioat_shutdown(struct pci_dev *pdev)
        ioat_disable_interrupts(ioat_dma);
 }
 
-void ioat_resume(struct ioatdma_device *ioat_dma)
+static void ioat_resume(struct ioatdma_device *ioat_dma)
 {
        struct ioatdma_chan *ioat_chan;
        u32 chanerr;
index 1ba2fd7..39de898 100644 (file)
@@ -102,6 +102,7 @@ struct k3_dma_dev {
        struct clk              *clk;
        u32                     dma_channels;
        u32                     dma_requests;
+       unsigned int            irq;
 };
 
 #define to_k3_dma(dmadev) container_of(dmadev, struct k3_dma_dev, slave)
@@ -425,10 +426,9 @@ static struct dma_async_tx_descriptor *k3_dma_prep_memcpy(
 
        num = DIV_ROUND_UP(len, DMA_MAX_SIZE);
        ds = kzalloc(sizeof(*ds) + num * sizeof(ds->desc_hw[0]), GFP_ATOMIC);
-       if (!ds) {
-               dev_dbg(chan->device->dev, "vchan %p: kzalloc fail\n", &c->vc);
+       if (!ds)
                return NULL;
-       }
+
        ds->desc_hw_lli = __virt_to_phys((unsigned long)&ds->desc_hw[0]);
        ds->size = len;
        ds->desc_num = num;
@@ -481,10 +481,9 @@ static struct dma_async_tx_descriptor *k3_dma_prep_slave_sg(
        }
 
        ds = kzalloc(sizeof(*ds) + num * sizeof(ds->desc_hw[0]), GFP_ATOMIC);
-       if (!ds) {
-               dev_dbg(chan->device->dev, "vchan %p: kzalloc fail\n", &c->vc);
+       if (!ds)
                return NULL;
-       }
+
        ds->desc_hw_lli = __virt_to_phys((unsigned long)&ds->desc_hw[0]);
        ds->desc_num = num;
        num = 0;
@@ -705,6 +704,8 @@ static int k3_dma_probe(struct platform_device *op)
        if (ret)
                return ret;
 
+       d->irq = irq;
+
        /* init phy channel */
        d->phy = devm_kzalloc(&op->dev,
                d->dma_channels * sizeof(struct k3_dma_phy), GFP_KERNEL);
@@ -759,7 +760,7 @@ static int k3_dma_probe(struct platform_device *op)
 
        ret = dma_async_device_register(&d->slave);
        if (ret)
-               return ret;
+               goto dma_async_register_fail;
 
        ret = of_dma_controller_register((&op->dev)->of_node,
                                        k3_of_dma_simple_xlate, d);
@@ -776,6 +777,8 @@ static int k3_dma_probe(struct platform_device *op)
 
 of_dma_register_fail:
        dma_async_device_unregister(&d->slave);
+dma_async_register_fail:
+       clk_disable_unprepare(d->clk);
        return ret;
 }
 
@@ -787,6 +790,8 @@ static int k3_dma_remove(struct platform_device *op)
        dma_async_device_unregister(&d->slave);
        of_dma_controller_free((&op->dev)->of_node);
 
+       devm_free_irq(&op->dev, d->irq, d);
+
        list_for_each_entry_safe(c, cn, &d->slave.channels, vc.chan.device_node) {
                list_del(&c->vc.chan.device_node);
                tasklet_kill(&c->vc.task);
index 56f1fd6..f4b25fb 100644 (file)
@@ -931,6 +931,25 @@ static void dma_do_tasklet(unsigned long data)
 static int mmp_pdma_remove(struct platform_device *op)
 {
        struct mmp_pdma_device *pdev = platform_get_drvdata(op);
+       struct mmp_pdma_phy *phy;
+       int i, irq = 0, irq_num = 0;
+
+
+       for (i = 0; i < pdev->dma_channels; i++) {
+               if (platform_get_irq(op, i) > 0)
+                       irq_num++;
+       }
+
+       if (irq_num != pdev->dma_channels) {
+               irq = platform_get_irq(op, 0);
+               devm_free_irq(&op->dev, irq, pdev);
+       } else {
+               for (i = 0; i < pdev->dma_channels; i++) {
+                       phy = &pdev->phy[i];
+                       irq = platform_get_irq(op, i);
+                       devm_free_irq(&op->dev, irq, phy);
+               }
+       }
 
        dma_async_device_unregister(&pdev->device);
        return 0;
index 3df0422..b3441f5 100644 (file)
@@ -404,7 +404,7 @@ static void mmp_tdma_free_chan_resources(struct dma_chan *chan)
        return;
 }
 
-struct mmp_tdma_desc *mmp_tdma_alloc_descriptor(struct mmp_tdma_chan *tdmac)
+static struct mmp_tdma_desc *mmp_tdma_alloc_descriptor(struct mmp_tdma_chan *tdmac)
 {
        struct gen_pool *gpool;
        int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc);
@@ -551,10 +551,9 @@ static int mmp_tdma_chan_init(struct mmp_tdma_device *tdev,
 
        /* alloc channel */
        tdmac = devm_kzalloc(tdev->dev, sizeof(*tdmac), GFP_KERNEL);
-       if (!tdmac) {
-               dev_err(tdev->dev, "no free memory for DMA channels!\n");
+       if (!tdmac)
                return -ENOMEM;
-       }
+
        if (irq)
                tdmac->irq = irq;
        tdmac->dev         = tdev->dev;
@@ -593,7 +592,7 @@ static bool mmp_tdma_filter_fn(struct dma_chan *chan, void *fn_param)
        return true;
 }
 
-struct dma_chan *mmp_tdma_xlate(struct of_phandle_args *dma_spec,
+static struct dma_chan *mmp_tdma_xlate(struct of_phandle_args *dma_spec,
                               struct of_dma *ofdma)
 {
        struct mmp_tdma_device *tdev = ofdma->of_dma_data;
index 631c443..a6e6427 100644 (file)
@@ -148,6 +148,7 @@ struct moxart_chan {
 struct moxart_dmadev {
        struct dma_device               dma_slave;
        struct moxart_chan              slave_chans[APB_DMA_MAX_CHANNEL];
+       unsigned int                    irq;
 };
 
 struct moxart_filter_data {
@@ -574,10 +575,8 @@ static int moxart_probe(struct platform_device *pdev)
        struct moxart_dmadev *mdc;
 
        mdc = devm_kzalloc(dev, sizeof(*mdc), GFP_KERNEL);
-       if (!mdc) {
-               dev_err(dev, "can't allocate DMA container\n");
+       if (!mdc)
                return -ENOMEM;
-       }
 
        irq = irq_of_parse_and_map(node, 0);
        if (irq == NO_IRQ) {
@@ -617,6 +616,7 @@ static int moxart_probe(struct platform_device *pdev)
                dev_err(dev, "devm_request_irq failed\n");
                return ret;
        }
+       mdc->irq = irq;
 
        ret = dma_async_device_register(&mdc->dma_slave);
        if (ret) {
@@ -640,6 +640,8 @@ static int moxart_remove(struct platform_device *pdev)
 {
        struct moxart_dmadev *m = platform_get_drvdata(pdev);
 
+       devm_free_irq(&pdev->dev, m->irq, m);
+
        dma_async_device_unregister(&m->dma_slave);
 
        if (pdev->dev.of_node)
index ccadafa..fa86592 100644 (file)
@@ -1110,6 +1110,7 @@ static int mpc_dma_remove(struct platform_device *op)
        }
        free_irq(mdma->irq, mdma);
        irq_dispose_mapping(mdma->irq);
+       tasklet_kill(&mdma->tasklet);
 
        return 0;
 }
index d0446a7..f4c9f98 100644 (file)
@@ -1057,7 +1057,7 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
 
 err_free_irq:
        free_irq(mv_chan->irq, mv_chan);
- err_free_dma:
+err_free_dma:
        dma_free_coherent(&pdev->dev, MV_XOR_POOL_SIZE,
                          mv_chan->dma_desc_pool_virt, mv_chan->dma_desc_pool);
        return ERR_PTR(ret);
diff --git a/drivers/dma/mv_xor_v2.c b/drivers/dma/mv_xor_v2.c
new file mode 100644 (file)
index 0000000..a28a01f
--- /dev/null
@@ -0,0 +1,878 @@
+/*
+ * Copyright (C) 2015-2016 Marvell International Ltd.
+
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#include "dmaengine.h"
+
+/* DMA Engine Registers */
+#define MV_XOR_V2_DMA_DESQ_BALR_OFF                    0x000
+#define MV_XOR_V2_DMA_DESQ_BAHR_OFF                    0x004
+#define MV_XOR_V2_DMA_DESQ_SIZE_OFF                    0x008
+#define MV_XOR_V2_DMA_DESQ_DONE_OFF                    0x00C
+#define   MV_XOR_V2_DMA_DESQ_DONE_PENDING_MASK         0x7FFF
+#define   MV_XOR_V2_DMA_DESQ_DONE_PENDING_SHIFT                0
+#define   MV_XOR_V2_DMA_DESQ_DONE_READ_PTR_MASK                0x1FFF
+#define   MV_XOR_V2_DMA_DESQ_DONE_READ_PTR_SHIFT       16
+#define MV_XOR_V2_DMA_DESQ_ARATTR_OFF                  0x010
+#define   MV_XOR_V2_DMA_DESQ_ATTR_CACHE_MASK           0x3F3F
+#define   MV_XOR_V2_DMA_DESQ_ATTR_OUTER_SHAREABLE      0x202
+#define   MV_XOR_V2_DMA_DESQ_ATTR_CACHEABLE            0x3C3C
+#define MV_XOR_V2_DMA_IMSG_CDAT_OFF                    0x014
+#define MV_XOR_V2_DMA_IMSG_THRD_OFF                    0x018
+#define   MV_XOR_V2_DMA_IMSG_THRD_MASK                 0x7FFF
+#define   MV_XOR_V2_DMA_IMSG_THRD_SHIFT                        0x0
+#define MV_XOR_V2_DMA_DESQ_AWATTR_OFF                  0x01C
+  /* Same flags as MV_XOR_V2_DMA_DESQ_ARATTR_OFF */
+#define MV_XOR_V2_DMA_DESQ_ALLOC_OFF                   0x04C
+#define   MV_XOR_V2_DMA_DESQ_ALLOC_WRPTR_MASK          0xFFFF
+#define   MV_XOR_V2_DMA_DESQ_ALLOC_WRPTR_SHIFT         16
+#define MV_XOR_V2_DMA_IMSG_BALR_OFF                    0x050
+#define MV_XOR_V2_DMA_IMSG_BAHR_OFF                    0x054
+#define MV_XOR_V2_DMA_DESQ_CTRL_OFF                    0x100
+#define          MV_XOR_V2_DMA_DESQ_CTRL_32B                   1
+#define   MV_XOR_V2_DMA_DESQ_CTRL_128B                 7
+#define MV_XOR_V2_DMA_DESQ_STOP_OFF                    0x800
+#define MV_XOR_V2_DMA_DESQ_DEALLOC_OFF                 0x804
+#define MV_XOR_V2_DMA_DESQ_ADD_OFF                     0x808
+
+/* XOR Global registers */
+#define MV_XOR_V2_GLOB_BW_CTRL                         0x4
+#define   MV_XOR_V2_GLOB_BW_CTRL_NUM_OSTD_RD_SHIFT     0
+#define   MV_XOR_V2_GLOB_BW_CTRL_NUM_OSTD_RD_VAL       64
+#define   MV_XOR_V2_GLOB_BW_CTRL_NUM_OSTD_WR_SHIFT     8
+#define   MV_XOR_V2_GLOB_BW_CTRL_NUM_OSTD_WR_VAL       8
+#define   MV_XOR_V2_GLOB_BW_CTRL_RD_BURST_LEN_SHIFT    12
+#define   MV_XOR_V2_GLOB_BW_CTRL_RD_BURST_LEN_VAL      4
+#define   MV_XOR_V2_GLOB_BW_CTRL_WR_BURST_LEN_SHIFT    16
+#define          MV_XOR_V2_GLOB_BW_CTRL_WR_BURST_LEN_VAL       4
+#define MV_XOR_V2_GLOB_PAUSE                           0x014
+#define   MV_XOR_V2_GLOB_PAUSE_AXI_TIME_DIS_VAL                0x8
+#define MV_XOR_V2_GLOB_SYS_INT_CAUSE                   0x200
+#define MV_XOR_V2_GLOB_SYS_INT_MASK                    0x204
+#define MV_XOR_V2_GLOB_MEM_INT_CAUSE                   0x220
+#define MV_XOR_V2_GLOB_MEM_INT_MASK                    0x224
+
+#define MV_XOR_V2_MIN_DESC_SIZE                                32
+#define MV_XOR_V2_EXT_DESC_SIZE                                128
+
+#define MV_XOR_V2_DESC_RESERVED_SIZE                   12
+#define MV_XOR_V2_DESC_BUFF_D_ADDR_SIZE                        12
+
+#define MV_XOR_V2_CMD_LINE_NUM_MAX_D_BUF               8
+
+/*
+ * Descriptors queue size. With 32 bytes descriptors, up to 2^14
+ * descriptors are allowed, with 128 bytes descriptors, up to 2^12
+ * descriptors are allowed. This driver uses 128 bytes descriptors,
+ * but experimentation has shown that a set of 1024 descriptors is
+ * sufficient to reach a good level of performance.
+ */
+#define MV_XOR_V2_DESC_NUM                             1024
+
+/**
+ * struct mv_xor_v2_descriptor - DMA HW descriptor
+ * @desc_id: used by S/W and is not affected by H/W.
+ * @flags: error and status flags
+ * @crc32_result: CRC32 calculation result
+ * @desc_ctrl: operation mode and control flags
+ * @buff_size: amount of bytes to be processed
+ * @fill_pattern_src_addr: Fill-Pattern or Source-Address and
+ * AW-Attributes
+ * @data_buff_addr: Source (and might be RAID6 destination)
+ * addresses of data buffers in RAID5 and RAID6
+ * @reserved: reserved
+ */
+struct mv_xor_v2_descriptor {
+       u16 desc_id;
+       u16 flags;
+       u32 crc32_result;
+       u32 desc_ctrl;
+
+       /* Definitions for desc_ctrl */
+#define DESC_NUM_ACTIVE_D_BUF_SHIFT    22
+#define DESC_OP_MODE_SHIFT             28
+#define DESC_OP_MODE_NOP               0       /* Idle operation */
+#define DESC_OP_MODE_MEMCPY            1       /* Pure-DMA operation */
+#define DESC_OP_MODE_MEMSET            2       /* Mem-Fill operation */
+#define DESC_OP_MODE_MEMINIT           3       /* Mem-Init operation */
+#define DESC_OP_MODE_MEM_COMPARE       4       /* Mem-Compare operation */
+#define DESC_OP_MODE_CRC32             5       /* CRC32 calculation */
+#define DESC_OP_MODE_XOR               6       /* RAID5 (XOR) operation */
+#define DESC_OP_MODE_RAID6             7       /* RAID6 P&Q-generation */
+#define DESC_OP_MODE_RAID6_REC         8       /* RAID6 Recovery */
+#define DESC_Q_BUFFER_ENABLE           BIT(16)
+#define DESC_P_BUFFER_ENABLE           BIT(17)
+#define DESC_IOD                       BIT(27)
+
+       u32 buff_size;
+       u32 fill_pattern_src_addr[4];
+       u32 data_buff_addr[MV_XOR_V2_DESC_BUFF_D_ADDR_SIZE];
+       u32 reserved[MV_XOR_V2_DESC_RESERVED_SIZE];
+};
+
+/**
+ * struct mv_xor_v2_device - implements a xor device
+ * @lock: lock for the engine
+ * @dma_base: memory mapped DMA register base
+ * @glob_base: memory mapped global register base
+ * @irq_tasklet:
+ * @free_sw_desc: linked list of free SW descriptors
+ * @dmadev: dma device
+ * @dmachan: dma channel
+ * @hw_desq: HW descriptors queue
+ * @hw_desq_virt: virtual address of DESCQ
+ * @sw_desq: SW descriptors queue
+ * @desc_size: HW descriptor size
+ * @npendings: number of pending descriptors (for which tx_submit has
+ * been called, but not yet issue_pending)
+ */
+struct mv_xor_v2_device {
+       spinlock_t lock;
+       void __iomem *dma_base;
+       void __iomem *glob_base;
+       struct clk *clk;
+       struct tasklet_struct irq_tasklet;
+       struct list_head free_sw_desc;
+       struct dma_device dmadev;
+       struct dma_chan dmachan;
+       dma_addr_t hw_desq;
+       struct mv_xor_v2_descriptor *hw_desq_virt;
+       struct mv_xor_v2_sw_desc *sw_desq;
+       int desc_size;
+       unsigned int npendings;
+};
+
+/**
+ * struct mv_xor_v2_sw_desc - implements a xor SW descriptor
+ * @idx: descriptor index
+ * @async_tx: support for the async_tx api
+ * @hw_desc: assosiated HW descriptor
+ * @free_list: node of the free SW descriprots list
+*/
+struct mv_xor_v2_sw_desc {
+       int idx;
+       struct dma_async_tx_descriptor async_tx;
+       struct mv_xor_v2_descriptor hw_desc;
+       struct list_head free_list;
+};
+
+/*
+ * Fill the data buffers to a HW descriptor
+ */
+static void mv_xor_v2_set_data_buffers(struct mv_xor_v2_device *xor_dev,
+                                       struct mv_xor_v2_descriptor *desc,
+                                       dma_addr_t src, int index)
+{
+       int arr_index = ((index >> 1) * 3);
+
+       /*
+        * Fill the buffer's addresses to the descriptor.
+        *
+        * The format of the buffers address for 2 sequential buffers
+        * X and X + 1:
+        *
+        *  First word:  Buffer-DX-Address-Low[31:0]
+        *  Second word: Buffer-DX+1-Address-Low[31:0]
+        *  Third word:  DX+1-Buffer-Address-High[47:32] [31:16]
+        *               DX-Buffer-Address-High[47:32] [15:0]
+        */
+       if ((index & 0x1) == 0) {
+               desc->data_buff_addr[arr_index] = lower_32_bits(src);
+
+               desc->data_buff_addr[arr_index + 2] &= ~0xFFFF;
+               desc->data_buff_addr[arr_index + 2] |=
+                       upper_32_bits(src) & 0xFFFF;
+       } else {
+               desc->data_buff_addr[arr_index + 1] =
+                       lower_32_bits(src);
+
+               desc->data_buff_addr[arr_index + 2] &= ~0xFFFF0000;
+               desc->data_buff_addr[arr_index + 2] |=
+                       (upper_32_bits(src) & 0xFFFF) << 16;
+       }
+}
+
+/*
+ * Return the next available index in the DESQ.
+ */
+static int mv_xor_v2_get_desq_write_ptr(struct mv_xor_v2_device *xor_dev)
+{
+       /* read the index for the next available descriptor in the DESQ */
+       u32 reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_ALLOC_OFF);
+
+       return ((reg >> MV_XOR_V2_DMA_DESQ_ALLOC_WRPTR_SHIFT)
+               & MV_XOR_V2_DMA_DESQ_ALLOC_WRPTR_MASK);
+}
+
+/*
+ * notify the engine of new descriptors, and update the available index.
+ */
+static void mv_xor_v2_add_desc_to_desq(struct mv_xor_v2_device *xor_dev,
+                                      int num_of_desc)
+{
+       /* write the number of new descriptors in the DESQ. */
+       writel(num_of_desc, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_ADD_OFF);
+}
+
+/*
+ * free HW descriptors
+ */
+static void mv_xor_v2_free_desc_from_desq(struct mv_xor_v2_device *xor_dev,
+                                         int num_of_desc)
+{
+       /* write the number of new descriptors in the DESQ. */
+       writel(num_of_desc, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_DEALLOC_OFF);
+}
+
+/*
+ * Set descriptor size
+ * Return the HW descriptor size in bytes
+ */
+static int mv_xor_v2_set_desc_size(struct mv_xor_v2_device *xor_dev)
+{
+       writel(MV_XOR_V2_DMA_DESQ_CTRL_128B,
+              xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_CTRL_OFF);
+
+       return MV_XOR_V2_EXT_DESC_SIZE;
+}
+
+/*
+ * Set the IMSG threshold
+ */
+static inline
+void mv_xor_v2_set_imsg_thrd(struct mv_xor_v2_device *xor_dev, int thrd_val)
+{
+       u32 reg;
+
+       reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_THRD_OFF);
+
+       reg &= (~MV_XOR_V2_DMA_IMSG_THRD_MASK << MV_XOR_V2_DMA_IMSG_THRD_SHIFT);
+       reg |= (thrd_val << MV_XOR_V2_DMA_IMSG_THRD_SHIFT);
+
+       writel(reg, xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_THRD_OFF);
+}
+
+static irqreturn_t mv_xor_v2_interrupt_handler(int irq, void *data)
+{
+       struct mv_xor_v2_device *xor_dev = data;
+       unsigned int ndescs;
+       u32 reg;
+
+       reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_DONE_OFF);
+
+       ndescs = ((reg >> MV_XOR_V2_DMA_DESQ_DONE_PENDING_SHIFT) &
+                 MV_XOR_V2_DMA_DESQ_DONE_PENDING_MASK);
+
+       /* No descriptors to process */
+       if (!ndescs)
+               return IRQ_NONE;
+
+       /*
+        * Update IMSG threshold, to disable new IMSG interrupts until
+        * end of the tasklet
+        */
+       mv_xor_v2_set_imsg_thrd(xor_dev, MV_XOR_V2_DESC_NUM);
+
+       /* schedule a tasklet to handle descriptors callbacks */
+       tasklet_schedule(&xor_dev->irq_tasklet);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * submit a descriptor to the DMA engine
+ */
+static dma_cookie_t
+mv_xor_v2_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+       int desq_ptr;
+       void *dest_hw_desc;
+       dma_cookie_t cookie;
+       struct mv_xor_v2_sw_desc *sw_desc =
+               container_of(tx, struct mv_xor_v2_sw_desc, async_tx);
+       struct mv_xor_v2_device *xor_dev =
+               container_of(tx->chan, struct mv_xor_v2_device, dmachan);
+
+       dev_dbg(xor_dev->dmadev.dev,
+               "%s sw_desc %p: async_tx %p\n",
+               __func__, sw_desc, &sw_desc->async_tx);
+
+       /* assign coookie */
+       spin_lock_bh(&xor_dev->lock);
+       cookie = dma_cookie_assign(tx);
+
+       /* get the next available slot in the DESQ */
+       desq_ptr = mv_xor_v2_get_desq_write_ptr(xor_dev);
+
+       /* copy the HW descriptor from the SW descriptor to the DESQ */
+       dest_hw_desc = xor_dev->hw_desq_virt + desq_ptr;
+
+       memcpy(dest_hw_desc, &sw_desc->hw_desc, xor_dev->desc_size);
+
+       xor_dev->npendings++;
+
+       spin_unlock_bh(&xor_dev->lock);
+
+       return cookie;
+}
+
+/*
+ * Prepare a SW descriptor
+ */
+static struct mv_xor_v2_sw_desc        *
+mv_xor_v2_prep_sw_desc(struct mv_xor_v2_device *xor_dev)
+{
+       struct mv_xor_v2_sw_desc *sw_desc;
+
+       /* Lock the channel */
+       spin_lock_bh(&xor_dev->lock);
+
+       if (list_empty(&xor_dev->free_sw_desc)) {
+               spin_unlock_bh(&xor_dev->lock);
+               /* schedule tasklet to free some descriptors */
+               tasklet_schedule(&xor_dev->irq_tasklet);
+               return NULL;
+       }
+
+       /* get a free SW descriptor from the SW DESQ */
+       sw_desc = list_first_entry(&xor_dev->free_sw_desc,
+                                  struct mv_xor_v2_sw_desc, free_list);
+       list_del(&sw_desc->free_list);
+
+       /* Release the channel */
+       spin_unlock_bh(&xor_dev->lock);
+
+       /* set the async tx descriptor */
+       dma_async_tx_descriptor_init(&sw_desc->async_tx, &xor_dev->dmachan);
+       sw_desc->async_tx.tx_submit = mv_xor_v2_tx_submit;
+       async_tx_ack(&sw_desc->async_tx);
+
+       return sw_desc;
+}
+
+/*
+ * Prepare a HW descriptor for a memcpy operation
+ */
+static struct dma_async_tx_descriptor *
+mv_xor_v2_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
+                         dma_addr_t src, size_t len, unsigned long flags)
+{
+       struct mv_xor_v2_sw_desc *sw_desc;
+       struct mv_xor_v2_descriptor *hw_descriptor;
+       struct mv_xor_v2_device *xor_dev;
+
+       xor_dev = container_of(chan, struct mv_xor_v2_device, dmachan);
+
+       dev_dbg(xor_dev->dmadev.dev,
+               "%s len: %zu src %pad dest %pad flags: %ld\n",
+               __func__, len, &src, &dest, flags);
+
+       sw_desc = mv_xor_v2_prep_sw_desc(xor_dev);
+
+       sw_desc->async_tx.flags = flags;
+
+       /* set the HW descriptor */
+       hw_descriptor = &sw_desc->hw_desc;
+
+       /* save the SW descriptor ID to restore when operation is done */
+       hw_descriptor->desc_id = sw_desc->idx;
+
+       /* Set the MEMCPY control word */
+       hw_descriptor->desc_ctrl =
+               DESC_OP_MODE_MEMCPY << DESC_OP_MODE_SHIFT;
+
+       if (flags & DMA_PREP_INTERRUPT)
+               hw_descriptor->desc_ctrl |= DESC_IOD;
+
+       /* Set source address */
+       hw_descriptor->fill_pattern_src_addr[0] = lower_32_bits(src);
+       hw_descriptor->fill_pattern_src_addr[1] =
+               upper_32_bits(src) & 0xFFFF;
+
+       /* Set Destination address */
+       hw_descriptor->fill_pattern_src_addr[2] = lower_32_bits(dest);
+       hw_descriptor->fill_pattern_src_addr[3] =
+               upper_32_bits(dest) & 0xFFFF;
+
+       /* Set buffers size */
+       hw_descriptor->buff_size = len;
+
+       /* return the async tx descriptor */
+       return &sw_desc->async_tx;
+}
+
+/*
+ * Prepare a HW descriptor for a XOR operation
+ */
+static struct dma_async_tx_descriptor *
+mv_xor_v2_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
+                      unsigned int src_cnt, size_t len, unsigned long flags)
+{
+       struct mv_xor_v2_sw_desc *sw_desc;
+       struct mv_xor_v2_descriptor *hw_descriptor;
+       struct mv_xor_v2_device *xor_dev =
+               container_of(chan, struct mv_xor_v2_device, dmachan);
+       int i;
+
+       if (src_cnt > MV_XOR_V2_CMD_LINE_NUM_MAX_D_BUF || src_cnt < 1)
+               return NULL;
+
+       dev_dbg(xor_dev->dmadev.dev,
+               "%s src_cnt: %d len: %zu dest %pad flags: %ld\n",
+               __func__, src_cnt, len, &dest, flags);
+
+       sw_desc = mv_xor_v2_prep_sw_desc(xor_dev);
+
+       sw_desc->async_tx.flags = flags;
+
+       /* set the HW descriptor */
+       hw_descriptor = &sw_desc->hw_desc;
+
+       /* save the SW descriptor ID to restore when operation is done */
+       hw_descriptor->desc_id = sw_desc->idx;
+
+       /* Set the XOR control word */
+       hw_descriptor->desc_ctrl =
+               DESC_OP_MODE_XOR << DESC_OP_MODE_SHIFT;
+       hw_descriptor->desc_ctrl |= DESC_P_BUFFER_ENABLE;
+
+       if (flags & DMA_PREP_INTERRUPT)
+               hw_descriptor->desc_ctrl |= DESC_IOD;
+
+       /* Set the data buffers */
+       for (i = 0; i < src_cnt; i++)
+               mv_xor_v2_set_data_buffers(xor_dev, hw_descriptor, src[i], i);
+
+       hw_descriptor->desc_ctrl |=
+               src_cnt << DESC_NUM_ACTIVE_D_BUF_SHIFT;
+
+       /* Set Destination address */
+       hw_descriptor->fill_pattern_src_addr[2] = lower_32_bits(dest);
+       hw_descriptor->fill_pattern_src_addr[3] =
+               upper_32_bits(dest) & 0xFFFF;
+
+       /* Set buffers size */
+       hw_descriptor->buff_size = len;
+
+       /* return the async tx descriptor */
+       return &sw_desc->async_tx;
+}
+
+/*
+ * Prepare a HW descriptor for interrupt operation.
+ */
+static struct dma_async_tx_descriptor *
+mv_xor_v2_prep_dma_interrupt(struct dma_chan *chan, unsigned long flags)
+{
+       struct mv_xor_v2_sw_desc *sw_desc;
+       struct mv_xor_v2_descriptor *hw_descriptor;
+       struct mv_xor_v2_device *xor_dev =
+               container_of(chan, struct mv_xor_v2_device, dmachan);
+
+       sw_desc = mv_xor_v2_prep_sw_desc(xor_dev);
+
+       /* set the HW descriptor */
+       hw_descriptor = &sw_desc->hw_desc;
+
+       /* save the SW descriptor ID to restore when operation is done */
+       hw_descriptor->desc_id = sw_desc->idx;
+
+       /* Set the INTERRUPT control word */
+       hw_descriptor->desc_ctrl =
+               DESC_OP_MODE_NOP << DESC_OP_MODE_SHIFT;
+       hw_descriptor->desc_ctrl |= DESC_IOD;
+
+       /* return the async tx descriptor */
+       return &sw_desc->async_tx;
+}
+
+/*
+ * push pending transactions to hardware
+ */
+static void mv_xor_v2_issue_pending(struct dma_chan *chan)
+{
+       struct mv_xor_v2_device *xor_dev =
+               container_of(chan, struct mv_xor_v2_device, dmachan);
+
+       spin_lock_bh(&xor_dev->lock);
+
+       /*
+        * update the engine with the number of descriptors to
+        * process
+        */
+       mv_xor_v2_add_desc_to_desq(xor_dev, xor_dev->npendings);
+       xor_dev->npendings = 0;
+
+       /* Activate the channel */
+       writel(0, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_STOP_OFF);
+
+       spin_unlock_bh(&xor_dev->lock);
+}
+
+static inline
+int mv_xor_v2_get_pending_params(struct mv_xor_v2_device *xor_dev,
+                                int *pending_ptr)
+{
+       u32 reg;
+
+       reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_DONE_OFF);
+
+       /* get the next pending descriptor index */
+       *pending_ptr = ((reg >> MV_XOR_V2_DMA_DESQ_DONE_READ_PTR_SHIFT) &
+                       MV_XOR_V2_DMA_DESQ_DONE_READ_PTR_MASK);
+
+       /* get the number of descriptors pending handle */
+       return ((reg >> MV_XOR_V2_DMA_DESQ_DONE_PENDING_SHIFT) &
+               MV_XOR_V2_DMA_DESQ_DONE_PENDING_MASK);
+}
+
+/*
+ * handle the descriptors after HW process
+ */
+static void mv_xor_v2_tasklet(unsigned long data)
+{
+       struct mv_xor_v2_device *xor_dev = (struct mv_xor_v2_device *) data;
+       int pending_ptr, num_of_pending, i;
+       struct mv_xor_v2_descriptor *next_pending_hw_desc = NULL;
+       struct mv_xor_v2_sw_desc *next_pending_sw_desc = NULL;
+
+       dev_dbg(xor_dev->dmadev.dev, "%s %d\n", __func__, __LINE__);
+
+       /* get the pending descriptors parameters */
+       num_of_pending = mv_xor_v2_get_pending_params(xor_dev, &pending_ptr);
+
+       /* next HW descriptor */
+       next_pending_hw_desc = xor_dev->hw_desq_virt + pending_ptr;
+
+       /* loop over free descriptors */
+       for (i = 0; i < num_of_pending; i++) {
+
+               if (pending_ptr > MV_XOR_V2_DESC_NUM)
+                       pending_ptr = 0;
+
+               if (next_pending_sw_desc != NULL)
+                       next_pending_hw_desc++;
+
+               /* get the SW descriptor related to the HW descriptor */
+               next_pending_sw_desc =
+                       &xor_dev->sw_desq[next_pending_hw_desc->desc_id];
+
+               /* call the callback */
+               if (next_pending_sw_desc->async_tx.cookie > 0) {
+                       /*
+                        * update the channel's completed cookie - no
+                        * lock is required the IMSG threshold provide
+                        * the locking
+                        */
+                       dma_cookie_complete(&next_pending_sw_desc->async_tx);
+
+                       if (next_pending_sw_desc->async_tx.callback)
+                               next_pending_sw_desc->async_tx.callback(
+                               next_pending_sw_desc->async_tx.callback_param);
+
+                       dma_descriptor_unmap(&next_pending_sw_desc->async_tx);
+               }
+
+               dma_run_dependencies(&next_pending_sw_desc->async_tx);
+
+               /* Lock the channel */
+               spin_lock_bh(&xor_dev->lock);
+
+               /* add the SW descriptor to the free descriptors list */
+               list_add(&next_pending_sw_desc->free_list,
+                        &xor_dev->free_sw_desc);
+
+               /* Release the channel */
+               spin_unlock_bh(&xor_dev->lock);
+
+               /* increment the next descriptor */
+               pending_ptr++;
+       }
+
+       if (num_of_pending != 0) {
+               /* free the descriptores */
+               mv_xor_v2_free_desc_from_desq(xor_dev, num_of_pending);
+       }
+
+       /* Update IMSG threshold, to enable new IMSG interrupts */
+       mv_xor_v2_set_imsg_thrd(xor_dev, 0);
+}
+
+/*
+ *     Set DMA Interrupt-message (IMSG) parameters
+ */
+static void mv_xor_v2_set_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
+{
+       struct mv_xor_v2_device *xor_dev = dev_get_drvdata(desc->dev);
+
+       writel(msg->address_lo,
+              xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_BALR_OFF);
+       writel(msg->address_hi & 0xFFFF,
+              xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_BAHR_OFF);
+       writel(msg->data,
+              xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_CDAT_OFF);
+}
+
+static int mv_xor_v2_descq_init(struct mv_xor_v2_device *xor_dev)
+{
+       u32 reg;
+
+       /* write the DESQ size to the DMA engine */
+       writel(MV_XOR_V2_DESC_NUM,
+              xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_SIZE_OFF);
+
+       /* write the DESQ address to the DMA enngine*/
+       writel(xor_dev->hw_desq & 0xFFFFFFFF,
+              xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_BALR_OFF);
+       writel((xor_dev->hw_desq & 0xFFFF00000000) >> 32,
+              xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_BAHR_OFF);
+
+       /* enable the DMA engine */
+       writel(0, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_STOP_OFF);
+
+       /*
+        * This is a temporary solution, until we activate the
+        * SMMU. Set the attributes for reading & writing data buffers
+        * & descriptors to:
+        *
+        *  - OuterShareable - Snoops will be performed on CPU caches
+        *  - Enable cacheable - Bufferable, Modifiable, Other Allocate
+        *    and Allocate
+        */
+       reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_ARATTR_OFF);
+       reg &= ~MV_XOR_V2_DMA_DESQ_ATTR_CACHE_MASK;
+       reg |= MV_XOR_V2_DMA_DESQ_ATTR_OUTER_SHAREABLE |
+               MV_XOR_V2_DMA_DESQ_ATTR_CACHEABLE;
+       writel(reg, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_ARATTR_OFF);
+
+       reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_AWATTR_OFF);
+       reg &= ~MV_XOR_V2_DMA_DESQ_ATTR_CACHE_MASK;
+       reg |= MV_XOR_V2_DMA_DESQ_ATTR_OUTER_SHAREABLE |
+               MV_XOR_V2_DMA_DESQ_ATTR_CACHEABLE;
+       writel(reg, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_AWATTR_OFF);
+
+       /* BW CTRL - set values to optimize the XOR performance:
+        *
+        *  - Set WrBurstLen & RdBurstLen - the unit will issue
+        *    maximum of 256B write/read transactions.
+        * -  Limit the number of outstanding write & read data
+        *    (OBB/IBB) requests to the maximal value.
+       */
+       reg = ((MV_XOR_V2_GLOB_BW_CTRL_NUM_OSTD_RD_VAL <<
+               MV_XOR_V2_GLOB_BW_CTRL_NUM_OSTD_RD_SHIFT) |
+              (MV_XOR_V2_GLOB_BW_CTRL_NUM_OSTD_WR_VAL  <<
+               MV_XOR_V2_GLOB_BW_CTRL_NUM_OSTD_WR_SHIFT) |
+              (MV_XOR_V2_GLOB_BW_CTRL_RD_BURST_LEN_VAL <<
+               MV_XOR_V2_GLOB_BW_CTRL_RD_BURST_LEN_SHIFT) |
+              (MV_XOR_V2_GLOB_BW_CTRL_WR_BURST_LEN_VAL <<
+               MV_XOR_V2_GLOB_BW_CTRL_WR_BURST_LEN_SHIFT));
+       writel(reg, xor_dev->glob_base + MV_XOR_V2_GLOB_BW_CTRL);
+
+       /* Disable the AXI timer feature */
+       reg = readl(xor_dev->glob_base + MV_XOR_V2_GLOB_PAUSE);
+       reg |= MV_XOR_V2_GLOB_PAUSE_AXI_TIME_DIS_VAL;
+       writel(reg, xor_dev->glob_base + MV_XOR_V2_GLOB_PAUSE);
+
+       return 0;
+}
+
+static int mv_xor_v2_probe(struct platform_device *pdev)
+{
+       struct mv_xor_v2_device *xor_dev;
+       struct resource *res;
+       int i, ret = 0;
+       struct dma_device *dma_dev;
+       struct mv_xor_v2_sw_desc *sw_desc;
+       struct msi_desc *msi_desc;
+
+       BUILD_BUG_ON(sizeof(struct mv_xor_v2_descriptor) !=
+                    MV_XOR_V2_EXT_DESC_SIZE);
+
+       xor_dev = devm_kzalloc(&pdev->dev, sizeof(*xor_dev), GFP_KERNEL);
+       if (!xor_dev)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       xor_dev->dma_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(xor_dev->dma_base))
+               return PTR_ERR(xor_dev->dma_base);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       xor_dev->glob_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(xor_dev->glob_base))
+               return PTR_ERR(xor_dev->glob_base);
+
+       platform_set_drvdata(pdev, xor_dev);
+
+       xor_dev->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(xor_dev->clk) && PTR_ERR(xor_dev->clk) == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       if (!IS_ERR(xor_dev->clk)) {
+               ret = clk_prepare_enable(xor_dev->clk);
+               if (ret)
+                       return ret;
+       }
+
+       ret = platform_msi_domain_alloc_irqs(&pdev->dev, 1,
+                                            mv_xor_v2_set_msi_msg);
+       if (ret)
+               goto disable_clk;
+
+       msi_desc = first_msi_entry(&pdev->dev);
+       if (!msi_desc)
+               goto free_msi_irqs;
+
+       ret = devm_request_irq(&pdev->dev, msi_desc->irq,
+                              mv_xor_v2_interrupt_handler, 0,
+                              dev_name(&pdev->dev), xor_dev);
+       if (ret)
+               goto free_msi_irqs;
+
+       tasklet_init(&xor_dev->irq_tasklet, mv_xor_v2_tasklet,
+                    (unsigned long) xor_dev);
+
+       xor_dev->desc_size = mv_xor_v2_set_desc_size(xor_dev);
+
+       dma_cookie_init(&xor_dev->dmachan);
+
+       /*
+        * allocate coherent memory for hardware descriptors
+        * note: writecombine gives slightly better performance, but
+        * requires that we explicitly flush the writes
+        */
+       xor_dev->hw_desq_virt =
+               dma_alloc_coherent(&pdev->dev,
+                                  xor_dev->desc_size * MV_XOR_V2_DESC_NUM,
+                                  &xor_dev->hw_desq, GFP_KERNEL);
+       if (!xor_dev->hw_desq_virt) {
+               ret = -ENOMEM;
+               goto free_msi_irqs;
+       }
+
+       /* alloc memory for the SW descriptors */
+       xor_dev->sw_desq = devm_kzalloc(&pdev->dev, sizeof(*sw_desc) *
+                                       MV_XOR_V2_DESC_NUM, GFP_KERNEL);
+       if (!xor_dev->sw_desq) {
+               ret = -ENOMEM;
+               goto free_hw_desq;
+       }
+
+       spin_lock_init(&xor_dev->lock);
+
+       /* init the free SW descriptors list */
+       INIT_LIST_HEAD(&xor_dev->free_sw_desc);
+
+       /* add all SW descriptors to the free list */
+       for (i = 0; i < MV_XOR_V2_DESC_NUM; i++) {
+               xor_dev->sw_desq[i].idx = i;
+               list_add(&xor_dev->sw_desq[i].free_list,
+                        &xor_dev->free_sw_desc);
+       }
+
+       dma_dev = &xor_dev->dmadev;
+
+       /* set DMA capabilities */
+       dma_cap_zero(dma_dev->cap_mask);
+       dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask);
+       dma_cap_set(DMA_XOR, dma_dev->cap_mask);
+       dma_cap_set(DMA_INTERRUPT, dma_dev->cap_mask);
+
+       /* init dma link list */
+       INIT_LIST_HEAD(&dma_dev->channels);
+
+       /* set base routines */
+       dma_dev->device_tx_status = dma_cookie_status;
+       dma_dev->device_issue_pending = mv_xor_v2_issue_pending;
+       dma_dev->dev = &pdev->dev;
+
+       dma_dev->device_prep_dma_memcpy = mv_xor_v2_prep_dma_memcpy;
+       dma_dev->device_prep_dma_interrupt = mv_xor_v2_prep_dma_interrupt;
+       dma_dev->max_xor = 8;
+       dma_dev->device_prep_dma_xor = mv_xor_v2_prep_dma_xor;
+
+       xor_dev->dmachan.device = dma_dev;
+
+       list_add_tail(&xor_dev->dmachan.device_node,
+                     &dma_dev->channels);
+
+       mv_xor_v2_descq_init(xor_dev);
+
+       ret = dma_async_device_register(dma_dev);
+       if (ret)
+               goto free_hw_desq;
+
+       dev_notice(&pdev->dev, "Marvell Version 2 XOR driver\n");
+
+       return 0;
+
+free_hw_desq:
+       dma_free_coherent(&pdev->dev,
+                         xor_dev->desc_size * MV_XOR_V2_DESC_NUM,
+                         xor_dev->hw_desq_virt, xor_dev->hw_desq);
+free_msi_irqs:
+       platform_msi_domain_free_irqs(&pdev->dev);
+disable_clk:
+       if (!IS_ERR(xor_dev->clk))
+               clk_disable_unprepare(xor_dev->clk);
+       return ret;
+}
+
+static int mv_xor_v2_remove(struct platform_device *pdev)
+{
+       struct mv_xor_v2_device *xor_dev = platform_get_drvdata(pdev);
+
+       dma_async_device_unregister(&xor_dev->dmadev);
+
+       dma_free_coherent(&pdev->dev,
+                         xor_dev->desc_size * MV_XOR_V2_DESC_NUM,
+                         xor_dev->hw_desq_virt, xor_dev->hw_desq);
+
+       platform_msi_domain_free_irqs(&pdev->dev);
+
+       clk_disable_unprepare(xor_dev->clk);
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mv_xor_v2_dt_ids[] = {
+       { .compatible = "marvell,xor-v2", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, mv_xor_v2_dt_ids);
+#endif
+
+static struct platform_driver mv_xor_v2_driver = {
+       .probe          = mv_xor_v2_probe,
+       .remove         = mv_xor_v2_remove,
+       .driver         = {
+               .name   = "mv_xor_v2",
+               .of_match_table = of_match_ptr(mv_xor_v2_dt_ids),
+       },
+};
+
+module_platform_driver(mv_xor_v2_driver);
+
+MODULE_DESCRIPTION("DMA engine driver for Marvell's Version 2 of XOR engine");
+MODULE_LICENSE("GPL");
index 2b5a198..08c45c1 100644 (file)
@@ -227,6 +227,7 @@ struct nbpf_device {
        void __iomem *base;
        struct clk *clk;
        const struct nbpf_config *config;
+       unsigned int eirq;
        struct nbpf_channel chan[];
 };
 
@@ -1300,10 +1301,9 @@ static int nbpf_probe(struct platform_device *pdev)
 
        nbpf = devm_kzalloc(dev, sizeof(*nbpf) + num_channels *
                            sizeof(nbpf->chan[0]), GFP_KERNEL);
-       if (!nbpf) {
-               dev_err(dev, "Memory allocation failed\n");
+       if (!nbpf)
                return -ENOMEM;
-       }
+
        dma_dev = &nbpf->dma_dev;
        dma_dev->dev = dev;
 
@@ -1376,6 +1376,7 @@ static int nbpf_probe(struct platform_device *pdev)
                               IRQF_SHARED, "dma error", nbpf);
        if (ret < 0)
                return ret;
+       nbpf->eirq = eirq;
 
        INIT_LIST_HEAD(&dma_dev->channels);
 
@@ -1447,6 +1448,17 @@ e_clk_off:
 static int nbpf_remove(struct platform_device *pdev)
 {
        struct nbpf_device *nbpf = platform_get_drvdata(pdev);
+       int i;
+
+       devm_free_irq(&pdev->dev, nbpf->eirq, nbpf);
+
+       for (i = 0; i < nbpf->config->num_channels; i++) {
+               struct nbpf_channel *chan = nbpf->chan + i;
+
+               devm_free_irq(&pdev->dev, chan->irq, chan);
+
+               tasklet_kill(&chan->tasklet);
+       }
 
        of_dma_controller_free(pdev->dev.of_node);
        dma_async_device_unregister(&nbpf->dma_dev);
index 1e984e1..d99ca2b 100644 (file)
@@ -59,6 +59,8 @@ struct omap_sg {
        dma_addr_t addr;
        uint32_t en;            /* number of elements (24-bit) */
        uint32_t fn;            /* number of frames (16-bit) */
+       int32_t fi;             /* for double indexing */
+       int16_t ei;             /* for double indexing */
 };
 
 struct omap_desc {
@@ -66,7 +68,8 @@ struct omap_desc {
        enum dma_transfer_direction dir;
        dma_addr_t dev_addr;
 
-       int16_t fi;             /* for OMAP_DMA_SYNC_PACKET */
+       int32_t fi;             /* for OMAP_DMA_SYNC_PACKET / double indexing */
+       int16_t ei;             /* for double indexing */
        uint8_t es;             /* CSDP_DATA_TYPE_xxx */
        uint32_t ccr;           /* CCR value */
        uint16_t clnk_ctrl;     /* CLNK_CTRL value */
@@ -379,8 +382,8 @@ static void omap_dma_start_sg(struct omap_chan *c, struct omap_desc *d,
        }
 
        omap_dma_chan_write(c, cxsa, sg->addr);
-       omap_dma_chan_write(c, cxei, 0);
-       omap_dma_chan_write(c, cxfi, 0);
+       omap_dma_chan_write(c, cxei, sg->ei);
+       omap_dma_chan_write(c, cxfi, sg->fi);
        omap_dma_chan_write(c, CEN, sg->en);
        omap_dma_chan_write(c, CFN, sg->fn);
 
@@ -425,7 +428,7 @@ static void omap_dma_start_desc(struct omap_chan *c)
        }
 
        omap_dma_chan_write(c, cxsa, d->dev_addr);
-       omap_dma_chan_write(c, cxei, 0);
+       omap_dma_chan_write(c, cxei, d->ei);
        omap_dma_chan_write(c, cxfi, d->fi);
        omap_dma_chan_write(c, CSDP, d->csdp);
        omap_dma_chan_write(c, CLNK_CTRL, d->clnk_ctrl);
@@ -971,6 +974,89 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_memcpy(
        return vchan_tx_prep(&c->vc, &d->vd, tx_flags);
 }
 
+static struct dma_async_tx_descriptor *omap_dma_prep_dma_interleaved(
+       struct dma_chan *chan, struct dma_interleaved_template *xt,
+       unsigned long flags)
+{
+       struct omap_chan *c = to_omap_dma_chan(chan);
+       struct omap_desc *d;
+       struct omap_sg *sg;
+       uint8_t data_type;
+       size_t src_icg, dst_icg;
+
+       /* Slave mode is not supported */
+       if (is_slave_direction(xt->dir))
+               return NULL;
+
+       if (xt->frame_size != 1 || xt->numf == 0)
+               return NULL;
+
+       d = kzalloc(sizeof(*d) + sizeof(d->sg[0]), GFP_ATOMIC);
+       if (!d)
+               return NULL;
+
+       data_type = __ffs((xt->src_start | xt->dst_start | xt->sgl[0].size));
+       if (data_type > CSDP_DATA_TYPE_32)
+               data_type = CSDP_DATA_TYPE_32;
+
+       sg = &d->sg[0];
+       d->dir = DMA_MEM_TO_MEM;
+       d->dev_addr = xt->src_start;
+       d->es = data_type;
+       sg->en = xt->sgl[0].size / BIT(data_type);
+       sg->fn = xt->numf;
+       sg->addr = xt->dst_start;
+       d->sglen = 1;
+       d->ccr = c->ccr;
+
+       src_icg = dmaengine_get_src_icg(xt, &xt->sgl[0]);
+       dst_icg = dmaengine_get_dst_icg(xt, &xt->sgl[0]);
+       if (src_icg) {
+               d->ccr |= CCR_SRC_AMODE_DBLIDX;
+               d->ei = 1;
+               d->fi = src_icg;
+       } else if (xt->src_inc) {
+               d->ccr |= CCR_SRC_AMODE_POSTINC;
+               d->fi = 0;
+       } else {
+               dev_err(chan->device->dev,
+                       "%s: SRC constant addressing is not supported\n",
+                       __func__);
+               kfree(d);
+               return NULL;
+       }
+
+       if (dst_icg) {
+               d->ccr |= CCR_DST_AMODE_DBLIDX;
+               sg->ei = 1;
+               sg->fi = dst_icg;
+       } else if (xt->dst_inc) {
+               d->ccr |= CCR_DST_AMODE_POSTINC;
+               sg->fi = 0;
+       } else {
+               dev_err(chan->device->dev,
+                       "%s: DST constant addressing is not supported\n",
+                       __func__);
+               kfree(d);
+               return NULL;
+       }
+
+       d->cicr = CICR_DROP_IE | CICR_FRAME_IE;
+
+       d->csdp = data_type;
+
+       if (dma_omap1()) {
+               d->cicr |= CICR_TOUT_IE;
+               d->csdp |= CSDP_DST_PORT_EMIFF | CSDP_SRC_PORT_EMIFF;
+       } else {
+               d->csdp |= CSDP_DST_PACKED | CSDP_SRC_PACKED;
+               d->cicr |= CICR_MISALIGNED_ERR_IE | CICR_TRANS_ERR_IE;
+               d->csdp |= CSDP_DST_BURST_64 | CSDP_SRC_BURST_64;
+       }
+
+       return vchan_tx_prep(&c->vc, &d->vd, flags);
+}
+
 static int omap_dma_slave_config(struct dma_chan *chan, struct dma_slave_config *cfg)
 {
        struct omap_chan *c = to_omap_dma_chan(chan);
@@ -1116,6 +1202,7 @@ static int omap_dma_probe(struct platform_device *pdev)
        dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
        dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask);
        dma_cap_set(DMA_MEMCPY, od->ddev.cap_mask);
+       dma_cap_set(DMA_INTERLEAVE, od->ddev.cap_mask);
        od->ddev.device_alloc_chan_resources = omap_dma_alloc_chan_resources;
        od->ddev.device_free_chan_resources = omap_dma_free_chan_resources;
        od->ddev.device_tx_status = omap_dma_tx_status;
@@ -1123,6 +1210,7 @@ static int omap_dma_probe(struct platform_device *pdev)
        od->ddev.device_prep_slave_sg = omap_dma_prep_slave_sg;
        od->ddev.device_prep_dma_cyclic = omap_dma_prep_dma_cyclic;
        od->ddev.device_prep_dma_memcpy = omap_dma_prep_dma_memcpy;
+       od->ddev.device_prep_interleaved_dma = omap_dma_prep_dma_interleaved;
        od->ddev.device_config = omap_dma_slave_config;
        od->ddev.device_pause = omap_dma_pause;
        od->ddev.device_resume = omap_dma_resume;
@@ -1204,10 +1292,14 @@ static int omap_dma_probe(struct platform_device *pdev)
 static int omap_dma_remove(struct platform_device *pdev)
 {
        struct omap_dmadev *od = platform_get_drvdata(pdev);
+       int irq;
 
        if (pdev->dev.of_node)
                of_dma_controller_free(pdev->dev.of_node);
 
+       irq = platform_get_irq(pdev, 1);
+       devm_free_irq(&pdev->dev, irq, od);
+
        dma_async_device_unregister(&od->ddev);
 
        if (!od->legacy) {
index 372b435..4fc3ffb 100644 (file)
@@ -2828,10 +2828,8 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 
        /* Allocate a new DMAC and its Channels */
        pl330 = devm_kzalloc(&adev->dev, sizeof(*pl330), GFP_KERNEL);
-       if (!pl330) {
-               dev_err(&adev->dev, "unable to allocate mem\n");
+       if (!pl330)
                return -ENOMEM;
-       }
 
        pd = &pl330->ddma;
        pd->dev = &adev->dev;
@@ -2890,7 +2888,6 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
        pl330->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL);
        if (!pl330->peripherals) {
                ret = -ENOMEM;
-               dev_err(&adev->dev, "unable to allocate pl330->peripherals\n");
                goto probe_err2;
        }
 
@@ -3005,12 +3002,18 @@ static int pl330_remove(struct amba_device *adev)
 {
        struct pl330_dmac *pl330 = amba_get_drvdata(adev);
        struct dma_pl330_chan *pch, *_p;
+       int i, irq;
 
        pm_runtime_get_noresume(pl330->ddma.dev);
 
        if (adev->dev.of_node)
                of_dma_controller_free(adev->dev.of_node);
 
+       for (i = 0; i < AMBA_NR_IRQS; i++) {
+               irq = adev->irq[i];
+               devm_free_irq(&adev->dev, irq, pl330);
+       }
+
        dma_async_device_unregister(&pl330->ddma);
 
        /* Idle the DMAC */
index 9217f89..da3688b 100644 (file)
@@ -4084,7 +4084,6 @@ static int ppc440spe_adma_probe(struct platform_device *ofdev)
        /* create a device */
        adev = kzalloc(sizeof(*adev), GFP_KERNEL);
        if (!adev) {
-               dev_err(&ofdev->dev, "failed to allocate device\n");
                initcode = PPC_ADMA_INIT_ALLOC;
                ret = -ENOMEM;
                goto err_adev_alloc;
@@ -4145,7 +4144,6 @@ static int ppc440spe_adma_probe(struct platform_device *ofdev)
        /* create a channel */
        chan = kzalloc(sizeof(*chan), GFP_KERNEL);
        if (!chan) {
-               dev_err(&ofdev->dev, "can't allocate channel structure\n");
                initcode = PPC_ADMA_INIT_CHANNEL;
                ret = -ENOMEM;
                goto err_chan_alloc;
index e756a30..dc7850a 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/of_device.h>
 #include <linux/of_dma.h>
 #include <linux/of.h>
+#include <linux/wait.h>
 #include <linux/dma/pxa-dma.h>
 
 #include "dmaengine.h"
@@ -118,6 +119,8 @@ struct pxad_chan {
        struct pxad_phy         *phy;
        struct dma_pool         *desc_pool;     /* Descriptors pool */
        dma_cookie_t            bus_error;
+
+       wait_queue_head_t       wq_state;
 };
 
 struct pxad_device {
@@ -318,7 +321,6 @@ static int dbg_open_##name(struct inode *inode, struct file *file) \
        return single_open(file, dbg_show_##name, inode->i_private); \
 } \
 static const struct file_operations dbg_fops_##name = { \
-       .owner          = THIS_MODULE, \
        .open           = dbg_open_##name, \
        .llseek         = seq_lseek, \
        .read           = seq_read, \
@@ -572,6 +574,7 @@ static void pxad_launch_chan(struct pxad_chan *chan,
         */
        phy_writel(chan->phy, desc->first, DDADR);
        phy_enable(chan->phy, chan->misaligned);
+       wake_up(&chan->wq_state);
 }
 
 static void set_updater_desc(struct pxad_desc_sw *sw_desc,
@@ -717,6 +720,7 @@ static irqreturn_t pxad_chan_handler(int irq, void *dev_id)
                }
        }
        spin_unlock_irqrestore(&chan->vc.lock, flags);
+       wake_up(&chan->wq_state);
 
        return IRQ_HANDLED;
 }
@@ -1268,6 +1272,14 @@ static enum dma_status pxad_tx_status(struct dma_chan *dchan,
        return ret;
 }
 
+static void pxad_synchronize(struct dma_chan *dchan)
+{
+       struct pxad_chan *chan = to_pxad_chan(dchan);
+
+       wait_event(chan->wq_state, !is_chan_running(chan));
+       vchan_synchronize(&chan->vc);
+}
+
 static void pxad_free_channels(struct dma_device *dmadev)
 {
        struct pxad_chan *c, *cn;
@@ -1372,6 +1384,7 @@ static int pxad_init_dmadev(struct platform_device *op,
        pdev->slave.device_tx_status = pxad_tx_status;
        pdev->slave.device_issue_pending = pxad_issue_pending;
        pdev->slave.device_config = pxad_config;
+       pdev->slave.device_synchronize = pxad_synchronize;
        pdev->slave.device_terminate_all = pxad_terminate_all;
 
        if (op->dev.coherent_dma_mask)
@@ -1389,6 +1402,7 @@ static int pxad_init_dmadev(struct platform_device *op,
                        return -ENOMEM;
                c->vc.desc_free = pxad_free_desc;
                vchan_init(&c->vc, &pdev->slave);
+               init_waitqueue_head(&c->wq_state);
        }
 
        return dma_async_device_register(&pdev->slave);
index 969b481..03c4eb3 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/of_dma.h>
 #include <linux/clk.h>
 #include <linux/dmaengine.h>
+#include <linux/pm_runtime.h>
 
 #include "../dmaengine.h"
 #include "../virt-dma.h"
@@ -58,6 +59,8 @@ struct bam_desc_hw {
        __le16 flags;
 };
 
+#define BAM_DMA_AUTOSUSPEND_DELAY 100
+
 #define DESC_FLAG_INT BIT(15)
 #define DESC_FLAG_EOT BIT(14)
 #define DESC_FLAG_EOB BIT(13)
@@ -527,12 +530,17 @@ static void bam_free_chan(struct dma_chan *chan)
        struct bam_device *bdev = bchan->bdev;
        u32 val;
        unsigned long flags;
+       int ret;
+
+       ret = pm_runtime_get_sync(bdev->dev);
+       if (ret < 0)
+               return;
 
        vchan_free_chan_resources(to_virt_chan(chan));
 
        if (bchan->curr_txd) {
                dev_err(bchan->bdev->dev, "Cannot free busy channel\n");
-               return;
+               goto err;
        }
 
        spin_lock_irqsave(&bchan->vc.lock, flags);
@@ -550,6 +558,10 @@ static void bam_free_chan(struct dma_chan *chan)
 
        /* disable irq */
        writel_relaxed(0, bam_addr(bdev, bchan->id, BAM_P_IRQ_EN));
+
+err:
+       pm_runtime_mark_last_busy(bdev->dev);
+       pm_runtime_put_autosuspend(bdev->dev);
 }
 
 /**
@@ -696,11 +708,18 @@ static int bam_pause(struct dma_chan *chan)
        struct bam_chan *bchan = to_bam_chan(chan);
        struct bam_device *bdev = bchan->bdev;
        unsigned long flag;
+       int ret;
+
+       ret = pm_runtime_get_sync(bdev->dev);
+       if (ret < 0)
+               return ret;
 
        spin_lock_irqsave(&bchan->vc.lock, flag);
        writel_relaxed(1, bam_addr(bdev, bchan->id, BAM_P_HALT));
        bchan->paused = 1;
        spin_unlock_irqrestore(&bchan->vc.lock, flag);
+       pm_runtime_mark_last_busy(bdev->dev);
+       pm_runtime_put_autosuspend(bdev->dev);
 
        return 0;
 }
@@ -715,11 +734,18 @@ static int bam_resume(struct dma_chan *chan)
        struct bam_chan *bchan = to_bam_chan(chan);
        struct bam_device *bdev = bchan->bdev;
        unsigned long flag;
+       int ret;
+
+       ret = pm_runtime_get_sync(bdev->dev);
+       if (ret < 0)
+               return ret;
 
        spin_lock_irqsave(&bchan->vc.lock, flag);
        writel_relaxed(0, bam_addr(bdev, bchan->id, BAM_P_HALT));
        bchan->paused = 0;
        spin_unlock_irqrestore(&bchan->vc.lock, flag);
+       pm_runtime_mark_last_busy(bdev->dev);
+       pm_runtime_put_autosuspend(bdev->dev);
 
        return 0;
 }
@@ -795,6 +821,7 @@ static irqreturn_t bam_dma_irq(int irq, void *data)
 {
        struct bam_device *bdev = data;
        u32 clr_mask = 0, srcs = 0;
+       int ret;
 
        srcs |= process_channel_irqs(bdev);
 
@@ -802,6 +829,10 @@ static irqreturn_t bam_dma_irq(int irq, void *data)
        if (srcs & P_IRQ)
                tasklet_schedule(&bdev->task);
 
+       ret = pm_runtime_get_sync(bdev->dev);
+       if (ret < 0)
+               return ret;
+
        if (srcs & BAM_IRQ) {
                clr_mask = readl_relaxed(bam_addr(bdev, 0, BAM_IRQ_STTS));
 
@@ -814,6 +845,9 @@ static irqreturn_t bam_dma_irq(int irq, void *data)
                writel_relaxed(clr_mask, bam_addr(bdev, 0, BAM_IRQ_CLR));
        }
 
+       pm_runtime_mark_last_busy(bdev->dev);
+       pm_runtime_put_autosuspend(bdev->dev);
+
        return IRQ_HANDLED;
 }
 
@@ -893,6 +927,7 @@ static void bam_start_dma(struct bam_chan *bchan)
        struct bam_desc_hw *desc;
        struct bam_desc_hw *fifo = PTR_ALIGN(bchan->fifo_virt,
                                        sizeof(struct bam_desc_hw));
+       int ret;
 
        lockdep_assert_held(&bchan->vc.lock);
 
@@ -904,6 +939,10 @@ static void bam_start_dma(struct bam_chan *bchan)
        async_desc = container_of(vd, struct bam_async_desc, vd);
        bchan->curr_txd = async_desc;
 
+       ret = pm_runtime_get_sync(bdev->dev);
+       if (ret < 0)
+               return;
+
        /* on first use, initialize the channel hardware */
        if (!bchan->initialized)
                bam_chan_init_hw(bchan, async_desc->dir);
@@ -946,6 +985,9 @@ static void bam_start_dma(struct bam_chan *bchan)
        wmb();
        writel_relaxed(bchan->tail * sizeof(struct bam_desc_hw),
                        bam_addr(bdev, bchan->id, BAM_P_EVNT_REG));
+
+       pm_runtime_mark_last_busy(bdev->dev);
+       pm_runtime_put_autosuspend(bdev->dev);
 }
 
 /**
@@ -970,6 +1012,7 @@ static void dma_tasklet(unsigned long data)
                        bam_start_dma(bchan);
                spin_unlock_irqrestore(&bchan->vc.lock, flags);
        }
+
 }
 
 /**
@@ -1213,6 +1256,13 @@ static int bam_dma_probe(struct platform_device *pdev)
        if (ret)
                goto err_unregister_dma;
 
+       pm_runtime_irq_safe(&pdev->dev);
+       pm_runtime_set_autosuspend_delay(&pdev->dev, BAM_DMA_AUTOSUSPEND_DELAY);
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_mark_last_busy(&pdev->dev);
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+
        return 0;
 
 err_unregister_dma:
@@ -1233,6 +1283,8 @@ static int bam_dma_remove(struct platform_device *pdev)
        struct bam_device *bdev = platform_get_drvdata(pdev);
        u32 i;
 
+       pm_runtime_force_suspend(&pdev->dev);
+
        of_dma_controller_free(pdev->dev.of_node);
        dma_async_device_unregister(&bdev->common);
 
@@ -1260,11 +1312,66 @@ static int bam_dma_remove(struct platform_device *pdev)
        return 0;
 }
 
+static int __maybe_unused bam_dma_runtime_suspend(struct device *dev)
+{
+       struct bam_device *bdev = dev_get_drvdata(dev);
+
+       clk_disable(bdev->bamclk);
+
+       return 0;
+}
+
+static int __maybe_unused bam_dma_runtime_resume(struct device *dev)
+{
+       struct bam_device *bdev = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_enable(bdev->bamclk);
+       if (ret < 0) {
+               dev_err(dev, "clk_enable failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __maybe_unused bam_dma_suspend(struct device *dev)
+{
+       struct bam_device *bdev = dev_get_drvdata(dev);
+
+       pm_runtime_force_suspend(dev);
+
+       clk_unprepare(bdev->bamclk);
+
+       return 0;
+}
+
+static int __maybe_unused bam_dma_resume(struct device *dev)
+{
+       struct bam_device *bdev = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare(bdev->bamclk);
+       if (ret)
+               return ret;
+
+       pm_runtime_force_resume(dev);
+
+       return 0;
+}
+
+static const struct dev_pm_ops bam_dma_pm_ops = {
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(bam_dma_suspend, bam_dma_resume)
+       SET_RUNTIME_PM_OPS(bam_dma_runtime_suspend, bam_dma_runtime_resume,
+                               NULL)
+};
+
 static struct platform_driver bam_dma_driver = {
        .probe = bam_dma_probe,
        .remove = bam_dma_remove,
        .driver = {
                .name = "bam-dma-engine",
+               .pm = &bam_dma_pm_ops,
                .of_match_table = bam_of_match,
        },
 };
index 41b5c6d..b2374cd 100644 (file)
@@ -708,6 +708,7 @@ static int hidma_remove(struct platform_device *pdev)
        pm_runtime_get_sync(dmadev->ddev.dev);
        dma_async_device_unregister(&dmadev->ddev);
        devm_free_irq(dmadev->ddev.dev, dmadev->irq, dmadev->lldev);
+       tasklet_kill(&dmadev->task);
        hidma_debug_uninit(dmadev);
        hidma_ll_uninit(dmadev->lldev);
        hidma_free(dmadev);
index f392900..ad20dfb 100644 (file)
@@ -831,6 +831,7 @@ int hidma_ll_uninit(struct hidma_lldev *lldev)
 
        required_bytes = sizeof(struct hidma_tre) * lldev->nr_tres;
        tasklet_kill(&lldev->task);
+       tasklet_kill(&lldev->rst_task);
        memset(lldev->trepool, 0, required_bytes);
        lldev->trepool = NULL;
        lldev->pending_tre_count = 0;
index c0e3653..82f36e4 100644 (file)
@@ -371,8 +371,8 @@ static int __init hidma_mgmt_of_populate_channels(struct device_node *np)
                pdevinfo.size_data = 0;
                pdevinfo.dma_mask = DMA_BIT_MASK(64);
                new_pdev = platform_device_register_full(&pdevinfo);
-               if (!new_pdev) {
-                       ret = -ENODEV;
+               if (IS_ERR(new_pdev)) {
+                       ret = PTR_ERR(new_pdev);
                        goto out;
                }
                of_dma_configure(&new_pdev->dev, child);
@@ -392,8 +392,7 @@ static int __init hidma_mgmt_init(void)
 #if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
        struct device_node *child;
 
-       for (child = of_find_matching_node(NULL, hidma_mgmt_match); child;
-            child = of_find_matching_node(child, hidma_mgmt_match)) {
+       for_each_matching_node(child, hidma_mgmt_match) {
                /* device tree based firmware here */
                hidma_mgmt_of_populate_channels(child);
                of_node_put(child);
index 17ccdfd..ce67075 100644 (file)
@@ -768,16 +768,12 @@ static enum dma_status s3c24xx_dma_tx_status(struct dma_chan *chan,
 
        spin_lock_irqsave(&s3cchan->vc.lock, flags);
        ret = dma_cookie_status(chan, cookie, txstate);
-       if (ret == DMA_COMPLETE) {
-               spin_unlock_irqrestore(&s3cchan->vc.lock, flags);
-               return ret;
-       }
 
        /*
         * There's no point calculating the residue if there's
         * no txstate to store the value.
         */
-       if (!txstate) {
+       if (ret == DMA_COMPLETE || !txstate) {
                spin_unlock_irqrestore(&s3cchan->vc.lock, flags);
                return ret;
        }
@@ -1105,11 +1101,8 @@ static int s3c24xx_dma_init_virtual_channels(struct s3c24xx_dma_engine *s3cdma,
         */
        for (i = 0; i < channels; i++) {
                chan = devm_kzalloc(dmadev->dev, sizeof(*chan), GFP_KERNEL);
-               if (!chan) {
-                       dev_err(dmadev->dev,
-                               "%s no memory for channel\n", __func__);
+               if (!chan)
                        return -ENOMEM;
-               }
 
                chan->id = i;
                chan->host = s3cdma;
@@ -1143,8 +1136,10 @@ static void s3c24xx_dma_free_virtual_channels(struct dma_device *dmadev)
        struct s3c24xx_dma_chan *next;
 
        list_for_each_entry_safe(chan,
-                                next, &dmadev->channels, vc.chan.device_node)
+                                next, &dmadev->channels, vc.chan.device_node) {
                list_del(&chan->vc.chan.device_node);
+               tasklet_kill(&chan->vc.task);
+       }
 }
 
 /* s3c2410, s3c2440 and s3c2442 have a 0x40 stride without separate clocks */
@@ -1366,6 +1361,18 @@ err_memcpy:
        return ret;
 }
 
+static void s3c24xx_dma_free_irq(struct platform_device *pdev,
+                               struct s3c24xx_dma_engine *s3cdma)
+{
+       int i;
+
+       for (i = 0; i < s3cdma->pdata->num_phy_channels; i++) {
+               struct s3c24xx_dma_phy *phy = &s3cdma->phy_chans[i];
+
+               devm_free_irq(&pdev->dev, phy->irq, phy);
+       }
+}
+
 static int s3c24xx_dma_remove(struct platform_device *pdev)
 {
        const struct s3c24xx_dma_platdata *pdata = dev_get_platdata(&pdev->dev);
@@ -1376,6 +1383,8 @@ static int s3c24xx_dma_remove(struct platform_device *pdev)
        dma_async_device_unregister(&s3cdma->slave);
        dma_async_device_unregister(&s3cdma->memcpy);
 
+       s3c24xx_dma_free_irq(pdev, s3cdma);
+
        s3c24xx_dma_free_virtual_channels(&s3cdma->slave);
        s3c24xx_dma_free_virtual_channels(&s3cdma->memcpy);
 
index dfb1792..0dd9538 100644 (file)
@@ -311,7 +311,7 @@ static bool rcar_dmac_chan_is_busy(struct rcar_dmac_chan *chan)
 {
        u32 chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
 
-       return (chcr & (RCAR_DMACHCR_DE | RCAR_DMACHCR_TE)) == RCAR_DMACHCR_DE;
+       return !!(chcr & (RCAR_DMACHCR_DE | RCAR_DMACHCR_TE));
 }
 
 static void rcar_dmac_chan_start_xfer(struct rcar_dmac_chan *chan)
@@ -510,7 +510,7 @@ static void rcar_dmac_desc_put(struct rcar_dmac_chan *chan,
 
        spin_lock_irqsave(&chan->lock, flags);
        list_splice_tail_init(&desc->chunks, &chan->desc.chunks_free);
-       list_add_tail(&desc->node, &chan->desc.free);
+       list_add(&desc->node, &chan->desc.free);
        spin_unlock_irqrestore(&chan->lock, flags);
 }
 
@@ -990,6 +990,8 @@ static void rcar_dmac_free_chan_resources(struct dma_chan *chan)
        list_splice_init(&rchan->desc.done, &list);
        list_splice_init(&rchan->desc.wait, &list);
 
+       rchan->desc.running = NULL;
+
        list_for_each_entry(desc, &list, node)
                rcar_dmac_realloc_hwdesc(rchan, desc, 0);
 
@@ -1143,19 +1145,46 @@ static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan,
        struct rcar_dmac_desc *desc = chan->desc.running;
        struct rcar_dmac_xfer_chunk *running = NULL;
        struct rcar_dmac_xfer_chunk *chunk;
+       enum dma_status status;
        unsigned int residue = 0;
        unsigned int dptr = 0;
 
        if (!desc)
                return 0;
 
+       /*
+        * If the cookie corresponds to a descriptor that has been completed
+        * there is no residue. The same check has already been performed by the
+        * caller but without holding the channel lock, so the descriptor could
+        * now be complete.
+        */
+       status = dma_cookie_status(&chan->chan, cookie, NULL);
+       if (status == DMA_COMPLETE)
+               return 0;
+
        /*
         * If the cookie doesn't correspond to the currently running transfer
         * then the descriptor hasn't been processed yet, and the residue is
         * equal to the full descriptor size.
         */
-       if (cookie != desc->async_tx.cookie)
-               return desc->size;
+       if (cookie != desc->async_tx.cookie) {
+               list_for_each_entry(desc, &chan->desc.pending, node) {
+                       if (cookie == desc->async_tx.cookie)
+                               return desc->size;
+               }
+               list_for_each_entry(desc, &chan->desc.active, node) {
+                       if (cookie == desc->async_tx.cookie)
+                               return desc->size;
+               }
+
+               /*
+                * No descriptor found for the cookie, there's thus no residue.
+                * This shouldn't happen if the calling driver passes a correct
+                * cookie value.
+                */
+               WARN(1, "No descriptor for cookie!");
+               return 0;
+       }
 
        /*
         * In descriptor mode the descriptor running pointer is not maintained
@@ -1202,6 +1231,10 @@ static enum dma_status rcar_dmac_tx_status(struct dma_chan *chan,
        residue = rcar_dmac_chan_get_residue(rchan, cookie);
        spin_unlock_irqrestore(&rchan->lock, flags);
 
+       /* if there's no residue, the cookie is complete */
+       if (!residue)
+               return DMA_COMPLETE;
+
        dma_set_residue(txstate, residue);
 
        return status;
index 80d8640..c94ffab 100644 (file)
@@ -532,11 +532,8 @@ static int sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
 
        sh_chan = devm_kzalloc(sdev->dma_dev.dev, sizeof(struct sh_dmae_chan),
                               GFP_KERNEL);
-       if (!sh_chan) {
-               dev_err(sdev->dma_dev.dev,
-                       "No free memory for allocating dma channels!\n");
+       if (!sh_chan)
                return -ENOMEM;
-       }
 
        schan = &sh_chan->shdma_chan;
        schan->max_xfer_len = SH_DMA_TCR_MAX + 1;
@@ -732,10 +729,8 @@ static int sh_dmae_probe(struct platform_device *pdev)
 
        shdev = devm_kzalloc(&pdev->dev, sizeof(struct sh_dmae_device),
                             GFP_KERNEL);
-       if (!shdev) {
-               dev_err(&pdev->dev, "Not enough memory\n");
+       if (!shdev)
                return -ENOMEM;
-       }
 
        dma_dev = &shdev->shdma_dev.dma_dev;
 
index 6da2eaa..69b9564 100644 (file)
@@ -245,11 +245,8 @@ static int sudmac_chan_probe(struct sudmac_device *su_dev, int id, int irq,
        int err;
 
        sc = devm_kzalloc(&pdev->dev, sizeof(struct sudmac_chan), GFP_KERNEL);
-       if (!sc) {
-               dev_err(sdev->dma_dev.dev,
-                       "No free memory for allocating dma channels!\n");
+       if (!sc)
                return -ENOMEM;
-       }
 
        schan = &sc->shdma_chan;
        schan->max_xfer_len = 64 * 1024 * 1024 - 1;
@@ -349,10 +346,8 @@ static int sudmac_probe(struct platform_device *pdev)
        err = -ENOMEM;
        su_dev = devm_kzalloc(&pdev->dev, sizeof(struct sudmac_device),
                              GFP_KERNEL);
-       if (!su_dev) {
-               dev_err(&pdev->dev, "Not enough memory\n");
+       if (!su_dev)
                return err;
-       }
 
        dma_dev = &su_dev->shdma_dev.dma_dev;
 
index e48350e..d8bc3f2 100644 (file)
@@ -854,10 +854,9 @@ static int sirfsoc_dma_probe(struct platform_device *op)
        int ret, i;
 
        sdma = devm_kzalloc(dev, sizeof(*sdma), GFP_KERNEL);
-       if (!sdma) {
-               dev_err(dev, "Memory exhausted!\n");
+       if (!sdma)
                return -ENOMEM;
-       }
+
        data = (struct sirfsoc_dmadata *)
                (of_match_device(op->dev.driver->of_match_table,
                                 &op->dev)->data);
@@ -981,6 +980,7 @@ static int sirfsoc_dma_remove(struct platform_device *op)
        of_dma_controller_free(op->dev.of_node);
        dma_async_device_unregister(&sdma->dma);
        free_irq(sdma->irq, sdma);
+       tasklet_kill(&sdma->tasklet);
        irq_dispose_mapping(sdma->irq);
        pm_runtime_disable(&op->dev);
        if (!pm_runtime_status_suspended(&op->dev))
@@ -1126,17 +1126,17 @@ static const struct dev_pm_ops sirfsoc_dma_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(sirfsoc_dma_pm_suspend, sirfsoc_dma_pm_resume)
 };
 
-struct sirfsoc_dmadata sirfsoc_dmadata_a6 = {
+static struct sirfsoc_dmadata sirfsoc_dmadata_a6 = {
        .exec = sirfsoc_dma_execute_hw_a6,
        .type = SIRFSOC_DMA_VER_A6,
 };
 
-struct sirfsoc_dmadata sirfsoc_dmadata_a7v1 = {
+static struct sirfsoc_dmadata sirfsoc_dmadata_a7v1 = {
        .exec = sirfsoc_dma_execute_hw_a7v1,
        .type = SIRFSOC_DMA_VER_A7V1,
 };
 
-struct sirfsoc_dmadata sirfsoc_dmadata_a7v2 = {
+static struct sirfsoc_dmadata sirfsoc_dmadata_a7v2 = {
        .exec = sirfsoc_dma_execute_hw_a7v2,
        .type = SIRFSOC_DMA_VER_A7V2,
 };
index 6fb8307..8b18e44 100644 (file)
@@ -2588,7 +2588,7 @@ static enum dma_status d40_tx_status(struct dma_chan *chan,
        }
 
        ret = dma_cookie_status(chan, cookie, txstate);
-       if (ret != DMA_COMPLETE)
+       if (ret != DMA_COMPLETE && txstate)
                dma_set_residue(txstate, stedma40_residue(chan));
 
        if (d40_is_paused(d40c))
@@ -3237,10 +3237,8 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
                       (num_phy_chans + num_log_chans + num_memcpy_chans) *
                       sizeof(struct d40_chan), GFP_KERNEL);
 
-       if (base == NULL) {
-               d40_err(&pdev->dev, "Out of memory\n");
+       if (base == NULL)
                goto failure;
-       }
 
        base->rev = rev;
        base->clk = clk;
index 27b818d..13b42dd 100644 (file)
@@ -10,7 +10,7 @@
 
 #include "ste_dma40_ll.h"
 
-u8 d40_width_to_bits(enum dma_slave_buswidth width)
+static u8 d40_width_to_bits(enum dma_slave_buswidth width)
 {
        if (width == DMA_SLAVE_BUSWIDTH_1_BYTE)
                return STEDMA40_ESIZE_8_BIT;
index 5065ca4..3835fcd 100644 (file)
@@ -865,7 +865,7 @@ static enum dma_status sun6i_dma_tx_status(struct dma_chan *chan,
        size_t bytes = 0;
 
        ret = dma_cookie_status(chan, cookie, state);
-       if (ret == DMA_COMPLETE)
+       if (ret == DMA_COMPLETE || !state)
                return ret;
 
        spin_lock_irqsave(&vchan->vc.lock, flags);
index 01e316f..6ab9eb9 100644 (file)
@@ -300,10 +300,8 @@ static struct tegra_dma_desc *tegra_dma_desc_get(
 
        /* Allocate DMA desc */
        dma_desc = kzalloc(sizeof(*dma_desc), GFP_NOWAIT);
-       if (!dma_desc) {
-               dev_err(tdc2dev(tdc), "dma_desc alloc failed\n");
+       if (!dma_desc)
                return NULL;
-       }
 
        dma_async_tx_descriptor_init(&dma_desc->txd, &tdc->dma_chan);
        dma_desc->txd.tx_submit = tegra_dma_tx_submit;
@@ -340,8 +338,7 @@ static struct tegra_dma_sg_req *tegra_dma_sg_req_get(
        spin_unlock_irqrestore(&tdc->lock, flags);
 
        sg_req = kzalloc(sizeof(struct tegra_dma_sg_req), GFP_NOWAIT);
-       if (!sg_req)
-               dev_err(tdc2dev(tdc), "sg_req alloc failed\n");
+
        return sg_req;
 }
 
@@ -484,7 +481,7 @@ static void tegra_dma_configure_for_next(struct tegra_dma_channel *tdc,
         * load new configuration.
         */
        tegra_dma_pause(tdc, false);
-       status  = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS);
+       status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS);
 
        /*
         * If interrupt is pending then do nothing as the ISR will handle
@@ -822,13 +819,8 @@ static enum dma_status tegra_dma_tx_status(struct dma_chan *dc,
        /* Check on wait_ack desc status */
        list_for_each_entry(dma_desc, &tdc->free_dma_desc, node) {
                if (dma_desc->txd.cookie == cookie) {
-                       residual =  dma_desc->bytes_requested -
-                                       (dma_desc->bytes_transferred %
-                                               dma_desc->bytes_requested);
-                       dma_set_residue(txstate, residual);
                        ret = dma_desc->dma_status;
-                       spin_unlock_irqrestore(&tdc->lock, flags);
-                       return ret;
+                       goto found;
                }
        }
 
@@ -836,17 +828,22 @@ static enum dma_status tegra_dma_tx_status(struct dma_chan *dc,
        list_for_each_entry(sg_req, &tdc->pending_sg_req, node) {
                dma_desc = sg_req->dma_desc;
                if (dma_desc->txd.cookie == cookie) {
-                       residual =  dma_desc->bytes_requested -
-                                       (dma_desc->bytes_transferred %
-                                               dma_desc->bytes_requested);
-                       dma_set_residue(txstate, residual);
                        ret = dma_desc->dma_status;
-                       spin_unlock_irqrestore(&tdc->lock, flags);
-                       return ret;
+                       goto found;
                }
        }
 
-       dev_dbg(tdc2dev(tdc), "cookie %d does not found\n", cookie);
+       dev_dbg(tdc2dev(tdc), "cookie %d not found\n", cookie);
+       dma_desc = NULL;
+
+found:
+       if (dma_desc && txstate) {
+               residual = dma_desc->bytes_requested -
+                          (dma_desc->bytes_transferred %
+                           dma_desc->bytes_requested);
+               dma_set_residue(txstate, residual);
+       }
+
        spin_unlock_irqrestore(&tdc->lock, flags);
        return ret;
 }
@@ -905,7 +902,6 @@ static int get_transfer_param(struct tegra_dma_channel *tdc,
        unsigned long *apb_seq, unsigned long *csr, unsigned int *burst_size,
        enum dma_slave_buswidth *slave_bw)
 {
-
        switch (direction) {
        case DMA_MEM_TO_DEV:
                *apb_addr = tdc->dma_sconfig.dst_addr;
@@ -948,8 +944,8 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg(
 {
        struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
        struct tegra_dma_desc *dma_desc;
-       unsigned int        i;
-       struct scatterlist      *sg;
+       unsigned int i;
+       struct scatterlist *sg;
        unsigned long csr, ahb_seq, apb_ptr, apb_seq;
        struct list_head req_list;
        struct tegra_dma_sg_req  *sg_req = NULL;
@@ -1062,7 +1058,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic(
 {
        struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
        struct tegra_dma_desc *dma_desc = NULL;
-       struct tegra_dma_sg_req  *sg_req = NULL;
+       struct tegra_dma_sg_req *sg_req = NULL;
        unsigned long csr, ahb_seq, apb_ptr, apb_seq;
        int len;
        size_t remain_len;
@@ -1204,7 +1200,6 @@ static void tegra_dma_free_chan_resources(struct dma_chan *dc)
 {
        struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
        struct tegra_dma *tdma = tdc->tdma;
-
        struct tegra_dma_desc *dma_desc;
        struct tegra_dma_sg_req *sg_req;
        struct list_head dma_desc_list;
@@ -1305,7 +1300,7 @@ static const struct tegra_dma_chip_data tegra148_dma_chip_data = {
 
 static int tegra_dma_probe(struct platform_device *pdev)
 {
-       struct resource *res;
+       struct resource *res;
        struct tegra_dma *tdma;
        int ret;
        int i;
@@ -1319,10 +1314,8 @@ static int tegra_dma_probe(struct platform_device *pdev)
 
        tdma = devm_kzalloc(&pdev->dev, sizeof(*tdma) + cdata->nr_channels *
                        sizeof(struct tegra_dma_channel), GFP_KERNEL);
-       if (!tdma) {
-               dev_err(&pdev->dev, "Error: memory allocation failed\n");
+       if (!tdma)
                return -ENOMEM;
-       }
 
        tdma->dev = &pdev->dev;
        tdma->chip_data = cdata;
index e107779..5ae294b 100644 (file)
@@ -452,7 +452,7 @@ static struct platform_driver ti_dma_xbar_driver = {
        .probe  = ti_dma_xbar_probe,
 };
 
-int omap_dmaxbar_init(void)
+static int omap_dmaxbar_init(void)
 {
        return platform_driver_register(&ti_dma_xbar_driver);
 }
index 559cd40..e82745a 100644 (file)
@@ -337,18 +337,14 @@ static struct timb_dma_desc *td_alloc_init_desc(struct timb_dma_chan *td_chan)
        int err;
 
        td_desc = kzalloc(sizeof(struct timb_dma_desc), GFP_KERNEL);
-       if (!td_desc) {
-               dev_err(chan2dev(chan), "Failed to alloc descriptor\n");
+       if (!td_desc)
                goto out;
-       }
 
        td_desc->desc_list_len = td_chan->desc_elems * TIMB_DMA_DESC_SIZE;
 
        td_desc->desc_list = kzalloc(td_desc->desc_list_len, GFP_KERNEL);
-       if (!td_desc->desc_list) {
-               dev_err(chan2dev(chan), "Failed to alloc descriptor\n");
+       if (!td_desc->desc_list)
                goto err;
-       }
 
        dma_async_tx_descriptor_init(&td_desc->txd, chan);
        td_desc->txd.tx_submit = td_tx_submit;
index 8849318..7632290 100644 (file)
@@ -1165,9 +1165,12 @@ static int txx9dmac_chan_remove(struct platform_device *pdev)
 {
        struct txx9dmac_chan *dc = platform_get_drvdata(pdev);
 
+
        dma_async_device_unregister(&dc->dma);
-       if (dc->irq >= 0)
+       if (dc->irq >= 0) {
+               devm_free_irq(&pdev->dev, dc->irq, dc);
                tasklet_kill(&dc->tasklet);
+       }
        dc->ddev->chan[pdev->id % TXX9_DMA_MAX_NR_CHANNELS] = NULL;
        return 0;
 }
@@ -1228,8 +1231,10 @@ static int txx9dmac_remove(struct platform_device *pdev)
        struct txx9dmac_dev *ddev = platform_get_drvdata(pdev);
 
        txx9dmac_off(ddev);
-       if (ddev->irq >= 0)
+       if (ddev->irq >= 0) {
+               devm_free_irq(&pdev->dev, ddev->irq, ddev);
                tasklet_kill(&ddev->tasklet);
+       }
        return 0;
 }
 
index 3c4e9f2..9e91f8f 100644 (file)
@@ -1 +1,2 @@
-obj-$(CONFIG_XILINX_VDMA) += xilinx_vdma.o
+obj-$(CONFIG_XILINX_DMA) += xilinx_dma.o
+obj-$(CONFIG_XILINX_ZYNQMP_DMA) += zynqmp_dma.o
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
new file mode 100644 (file)
index 0000000..4e223d0
--- /dev/null
@@ -0,0 +1,2689 @@
+/*
+ * DMA driver for Xilinx Video DMA Engine
+ *
+ * Copyright (C) 2010-2014 Xilinx, Inc. All rights reserved.
+ *
+ * Based on the Freescale DMA driver.
+ *
+ * Description:
+ * The AXI Video Direct Memory Access (AXI VDMA) core is a soft Xilinx IP
+ * core that provides high-bandwidth direct memory access between memory
+ * and AXI4-Stream type video target peripherals. The core provides efficient
+ * two dimensional DMA operations with independent asynchronous read (S2MM)
+ * and write (MM2S) channel operation. It can be configured to have either
+ * one channel or two channels. If configured as two channels, one is to
+ * transmit to the video device (MM2S) and another is to receive from the
+ * video device (S2MM). Initialization, status, interrupt and management
+ * registers are accessed through an AXI4-Lite slave interface.
+ *
+ * The AXI Direct Memory Access (AXI DMA) core is a soft Xilinx IP core that
+ * provides high-bandwidth one dimensional direct memory access between memory
+ * and AXI4-Stream target peripherals. It supports one receive and one
+ * transmit channel, both of them optional at synthesis time.
+ *
+ * The AXI CDMA, is a soft IP, which provides high-bandwidth Direct Memory
+ * Access (DMA) between a memory-mapped source address and a memory-mapped
+ * destination address.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/bitops.h>
+#include <linux/dmapool.h>
+#include <linux/dma/xilinx_dma.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_dma.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+
+#include "../dmaengine.h"
+
+/* Register/Descriptor Offsets */
+#define XILINX_DMA_MM2S_CTRL_OFFSET            0x0000
+#define XILINX_DMA_S2MM_CTRL_OFFSET            0x0030
+#define XILINX_VDMA_MM2S_DESC_OFFSET           0x0050
+#define XILINX_VDMA_S2MM_DESC_OFFSET           0x00a0
+
+/* Control Registers */
+#define XILINX_DMA_REG_DMACR                   0x0000
+#define XILINX_DMA_DMACR_DELAY_MAX             0xff
+#define XILINX_DMA_DMACR_DELAY_SHIFT           24
+#define XILINX_DMA_DMACR_FRAME_COUNT_MAX       0xff
+#define XILINX_DMA_DMACR_FRAME_COUNT_SHIFT     16
+#define XILINX_DMA_DMACR_ERR_IRQ               BIT(14)
+#define XILINX_DMA_DMACR_DLY_CNT_IRQ           BIT(13)
+#define XILINX_DMA_DMACR_FRM_CNT_IRQ           BIT(12)
+#define XILINX_DMA_DMACR_MASTER_SHIFT          8
+#define XILINX_DMA_DMACR_FSYNCSRC_SHIFT        5
+#define XILINX_DMA_DMACR_FRAMECNT_EN           BIT(4)
+#define XILINX_DMA_DMACR_GENLOCK_EN            BIT(3)
+#define XILINX_DMA_DMACR_RESET                 BIT(2)
+#define XILINX_DMA_DMACR_CIRC_EN               BIT(1)
+#define XILINX_DMA_DMACR_RUNSTOP               BIT(0)
+#define XILINX_DMA_DMACR_FSYNCSRC_MASK         GENMASK(6, 5)
+
+#define XILINX_DMA_REG_DMASR                   0x0004
+#define XILINX_DMA_DMASR_EOL_LATE_ERR          BIT(15)
+#define XILINX_DMA_DMASR_ERR_IRQ               BIT(14)
+#define XILINX_DMA_DMASR_DLY_CNT_IRQ           BIT(13)
+#define XILINX_DMA_DMASR_FRM_CNT_IRQ           BIT(12)
+#define XILINX_DMA_DMASR_SOF_LATE_ERR          BIT(11)
+#define XILINX_DMA_DMASR_SG_DEC_ERR            BIT(10)
+#define XILINX_DMA_DMASR_SG_SLV_ERR            BIT(9)
+#define XILINX_DMA_DMASR_EOF_EARLY_ERR         BIT(8)
+#define XILINX_DMA_DMASR_SOF_EARLY_ERR         BIT(7)
+#define XILINX_DMA_DMASR_DMA_DEC_ERR           BIT(6)
+#define XILINX_DMA_DMASR_DMA_SLAVE_ERR         BIT(5)
+#define XILINX_DMA_DMASR_DMA_INT_ERR           BIT(4)
+#define XILINX_DMA_DMASR_IDLE                  BIT(1)
+#define XILINX_DMA_DMASR_HALTED                BIT(0)
+#define XILINX_DMA_DMASR_DELAY_MASK            GENMASK(31, 24)
+#define XILINX_DMA_DMASR_FRAME_COUNT_MASK      GENMASK(23, 16)
+
+#define XILINX_DMA_REG_CURDESC                 0x0008
+#define XILINX_DMA_REG_TAILDESC                0x0010
+#define XILINX_DMA_REG_REG_INDEX               0x0014
+#define XILINX_DMA_REG_FRMSTORE                0x0018
+#define XILINX_DMA_REG_THRESHOLD               0x001c
+#define XILINX_DMA_REG_FRMPTR_STS              0x0024
+#define XILINX_DMA_REG_PARK_PTR                0x0028
+#define XILINX_DMA_PARK_PTR_WR_REF_SHIFT       8
+#define XILINX_DMA_PARK_PTR_RD_REF_SHIFT       0
+#define XILINX_DMA_REG_VDMA_VERSION            0x002c
+
+/* Register Direct Mode Registers */
+#define XILINX_DMA_REG_VSIZE                   0x0000
+#define XILINX_DMA_REG_HSIZE                   0x0004
+
+#define XILINX_DMA_REG_FRMDLY_STRIDE           0x0008
+#define XILINX_DMA_FRMDLY_STRIDE_FRMDLY_SHIFT  24
+#define XILINX_DMA_FRMDLY_STRIDE_STRIDE_SHIFT  0
+
+#define XILINX_VDMA_REG_START_ADDRESS(n)       (0x000c + 4 * (n))
+#define XILINX_VDMA_REG_START_ADDRESS_64(n)    (0x000c + 8 * (n))
+
+/* HW specific definitions */
+#define XILINX_DMA_MAX_CHANS_PER_DEVICE        0x20
+
+#define XILINX_DMA_DMAXR_ALL_IRQ_MASK  \
+               (XILINX_DMA_DMASR_FRM_CNT_IRQ | \
+                XILINX_DMA_DMASR_DLY_CNT_IRQ | \
+                XILINX_DMA_DMASR_ERR_IRQ)
+
+#define XILINX_DMA_DMASR_ALL_ERR_MASK  \
+               (XILINX_DMA_DMASR_EOL_LATE_ERR | \
+                XILINX_DMA_DMASR_SOF_LATE_ERR | \
+                XILINX_DMA_DMASR_SG_DEC_ERR | \
+                XILINX_DMA_DMASR_SG_SLV_ERR | \
+                XILINX_DMA_DMASR_EOF_EARLY_ERR | \
+                XILINX_DMA_DMASR_SOF_EARLY_ERR | \
+                XILINX_DMA_DMASR_DMA_DEC_ERR | \
+                XILINX_DMA_DMASR_DMA_SLAVE_ERR | \
+                XILINX_DMA_DMASR_DMA_INT_ERR)
+
+/*
+ * Recoverable errors are DMA Internal error, SOF Early, EOF Early
+ * and SOF Late. They are only recoverable when C_FLUSH_ON_FSYNC
+ * is enabled in the h/w system.
+ */
+#define XILINX_DMA_DMASR_ERR_RECOVER_MASK      \
+               (XILINX_DMA_DMASR_SOF_LATE_ERR | \
+                XILINX_DMA_DMASR_EOF_EARLY_ERR | \
+                XILINX_DMA_DMASR_SOF_EARLY_ERR | \
+                XILINX_DMA_DMASR_DMA_INT_ERR)
+
+/* Axi VDMA Flush on Fsync bits */
+#define XILINX_DMA_FLUSH_S2MM          3
+#define XILINX_DMA_FLUSH_MM2S          2
+#define XILINX_DMA_FLUSH_BOTH          1
+
+/* Delay loop counter to prevent hardware failure */
+#define XILINX_DMA_LOOP_COUNT          1000000
+
+/* AXI DMA Specific Registers/Offsets */
+#define XILINX_DMA_REG_SRCDSTADDR      0x18
+#define XILINX_DMA_REG_BTT             0x28
+
+/* AXI DMA Specific Masks/Bit fields */
+#define XILINX_DMA_MAX_TRANS_LEN       GENMASK(22, 0)
+#define XILINX_DMA_CR_COALESCE_MAX     GENMASK(23, 16)
+#define XILINX_DMA_CR_CYCLIC_BD_EN_MASK        BIT(4)
+#define XILINX_DMA_CR_COALESCE_SHIFT   16
+#define XILINX_DMA_BD_SOP              BIT(27)
+#define XILINX_DMA_BD_EOP              BIT(26)
+#define XILINX_DMA_COALESCE_MAX                255
+#define XILINX_DMA_NUM_APP_WORDS       5
+
+/* Multi-Channel DMA Descriptor offsets*/
+#define XILINX_DMA_MCRX_CDESC(x)       (0x40 + (x-1) * 0x20)
+#define XILINX_DMA_MCRX_TDESC(x)       (0x48 + (x-1) * 0x20)
+
+/* Multi-Channel DMA Masks/Shifts */
+#define XILINX_DMA_BD_HSIZE_MASK       GENMASK(15, 0)
+#define XILINX_DMA_BD_STRIDE_MASK      GENMASK(15, 0)
+#define XILINX_DMA_BD_VSIZE_MASK       GENMASK(31, 19)
+#define XILINX_DMA_BD_TDEST_MASK       GENMASK(4, 0)
+#define XILINX_DMA_BD_STRIDE_SHIFT     0
+#define XILINX_DMA_BD_VSIZE_SHIFT      19
+
+/* AXI CDMA Specific Registers/Offsets */
+#define XILINX_CDMA_REG_SRCADDR                0x18
+#define XILINX_CDMA_REG_DSTADDR                0x20
+
+/* AXI CDMA Specific Masks */
+#define XILINX_CDMA_CR_SGMODE          BIT(3)
+
+/**
+ * struct xilinx_vdma_desc_hw - Hardware Descriptor
+ * @next_desc: Next Descriptor Pointer @0x00
+ * @pad1: Reserved @0x04
+ * @buf_addr: Buffer address @0x08
+ * @buf_addr_msb: MSB of Buffer address @0x0C
+ * @vsize: Vertical Size @0x10
+ * @hsize: Horizontal Size @0x14
+ * @stride: Number of bytes between the first
+ *         pixels of each horizontal line @0x18
+ */
+struct xilinx_vdma_desc_hw {
+       u32 next_desc;
+       u32 pad1;
+       u32 buf_addr;
+       u32 buf_addr_msb;
+       u32 vsize;
+       u32 hsize;
+       u32 stride;
+} __aligned(64);
+
+/**
+ * struct xilinx_axidma_desc_hw - Hardware Descriptor for AXI DMA
+ * @next_desc: Next Descriptor Pointer @0x00
+ * @next_desc_msb: MSB of Next Descriptor Pointer @0x04
+ * @buf_addr: Buffer address @0x08
+ * @buf_addr_msb: MSB of Buffer address @0x0C
+ * @pad1: Reserved @0x10
+ * @pad2: Reserved @0x14
+ * @control: Control field @0x18
+ * @status: Status field @0x1C
+ * @app: APP Fields @0x20 - 0x30
+ */
+struct xilinx_axidma_desc_hw {
+       u32 next_desc;
+       u32 next_desc_msb;
+       u32 buf_addr;
+       u32 buf_addr_msb;
+       u32 mcdma_control;
+       u32 vsize_stride;
+       u32 control;
+       u32 status;
+       u32 app[XILINX_DMA_NUM_APP_WORDS];
+} __aligned(64);
+
+/**
+ * struct xilinx_cdma_desc_hw - Hardware Descriptor
+ * @next_desc: Next Descriptor Pointer @0x00
+ * @next_descmsb: Next Descriptor Pointer MSB @0x04
+ * @src_addr: Source address @0x08
+ * @src_addrmsb: Source address MSB @0x0C
+ * @dest_addr: Destination address @0x10
+ * @dest_addrmsb: Destination address MSB @0x14
+ * @control: Control field @0x18
+ * @status: Status field @0x1C
+ */
+struct xilinx_cdma_desc_hw {
+       u32 next_desc;
+       u32 next_desc_msb;
+       u32 src_addr;
+       u32 src_addr_msb;
+       u32 dest_addr;
+       u32 dest_addr_msb;
+       u32 control;
+       u32 status;
+} __aligned(64);
+
+/**
+ * struct xilinx_vdma_tx_segment - Descriptor segment
+ * @hw: Hardware descriptor
+ * @node: Node in the descriptor segments list
+ * @phys: Physical address of segment
+ */
+struct xilinx_vdma_tx_segment {
+       struct xilinx_vdma_desc_hw hw;
+       struct list_head node;
+       dma_addr_t phys;
+} __aligned(64);
+
+/**
+ * struct xilinx_axidma_tx_segment - Descriptor segment
+ * @hw: Hardware descriptor
+ * @node: Node in the descriptor segments list
+ * @phys: Physical address of segment
+ */
+struct xilinx_axidma_tx_segment {
+       struct xilinx_axidma_desc_hw hw;
+       struct list_head node;
+       dma_addr_t phys;
+} __aligned(64);
+
+/**
+ * struct xilinx_cdma_tx_segment - Descriptor segment
+ * @hw: Hardware descriptor
+ * @node: Node in the descriptor segments list
+ * @phys: Physical address of segment
+ */
+struct xilinx_cdma_tx_segment {
+       struct xilinx_cdma_desc_hw hw;
+       struct list_head node;
+       dma_addr_t phys;
+} __aligned(64);
+
+/**
+ * struct xilinx_dma_tx_descriptor - Per Transaction structure
+ * @async_tx: Async transaction descriptor
+ * @segments: TX segments list
+ * @node: Node in the channel descriptors list
+ * @cyclic: Check for cyclic transfers.
+ */
+struct xilinx_dma_tx_descriptor {
+       struct dma_async_tx_descriptor async_tx;
+       struct list_head segments;
+       struct list_head node;
+       bool cyclic;
+};
+
+/**
+ * struct xilinx_dma_chan - Driver specific DMA channel structure
+ * @xdev: Driver specific device structure
+ * @ctrl_offset: Control registers offset
+ * @desc_offset: TX descriptor registers offset
+ * @lock: Descriptor operation lock
+ * @pending_list: Descriptors waiting
+ * @active_list: Descriptors ready to submit
+ * @done_list: Complete descriptors
+ * @common: DMA common channel
+ * @desc_pool: Descriptors pool
+ * @dev: The dma device
+ * @irq: Channel IRQ
+ * @id: Channel ID
+ * @direction: Transfer direction
+ * @num_frms: Number of frames
+ * @has_sg: Support scatter transfers
+ * @cyclic: Check for cyclic transfers.
+ * @genlock: Support genlock mode
+ * @err: Channel has errors
+ * @tasklet: Cleanup work after irq
+ * @config: Device configuration info
+ * @flush_on_fsync: Flush on Frame sync
+ * @desc_pendingcount: Descriptor pending count
+ * @ext_addr: Indicates 64 bit addressing is supported by dma channel
+ * @desc_submitcount: Descriptor h/w submitted count
+ * @residue: Residue for AXI DMA
+ * @seg_v: Statically allocated segments base
+ * @cyclic_seg_v: Statically allocated segment base for cyclic transfers
+ * @start_transfer: Differentiate b/w DMA IP's transfer
+ */
+struct xilinx_dma_chan {
+       struct xilinx_dma_device *xdev;
+       u32 ctrl_offset;
+       u32 desc_offset;
+       spinlock_t lock;
+       struct list_head pending_list;
+       struct list_head active_list;
+       struct list_head done_list;
+       struct dma_chan common;
+       struct dma_pool *desc_pool;
+       struct device *dev;
+       int irq;
+       int id;
+       enum dma_transfer_direction direction;
+       int num_frms;
+       bool has_sg;
+       bool cyclic;
+       bool genlock;
+       bool err;
+       struct tasklet_struct tasklet;
+       struct xilinx_vdma_config config;
+       bool flush_on_fsync;
+       u32 desc_pendingcount;
+       bool ext_addr;
+       u32 desc_submitcount;
+       u32 residue;
+       struct xilinx_axidma_tx_segment *seg_v;
+       struct xilinx_axidma_tx_segment *cyclic_seg_v;
+       void (*start_transfer)(struct xilinx_dma_chan *chan);
+       u16 tdest;
+};
+
+struct xilinx_dma_config {
+       enum xdma_ip_type dmatype;
+       int (*clk_init)(struct platform_device *pdev, struct clk **axi_clk,
+                       struct clk **tx_clk, struct clk **txs_clk,
+                       struct clk **rx_clk, struct clk **rxs_clk);
+};
+
+/**
+ * struct xilinx_dma_device - DMA device structure
+ * @regs: I/O mapped base address
+ * @dev: Device Structure
+ * @common: DMA device structure
+ * @chan: Driver specific DMA channel
+ * @has_sg: Specifies whether Scatter-Gather is present or not
+ * @mcdma: Specifies whether Multi-Channel is present or not
+ * @flush_on_fsync: Flush on frame sync
+ * @ext_addr: Indicates 64 bit addressing is supported by dma device
+ * @pdev: Platform device structure pointer
+ * @dma_config: DMA config structure
+ * @axi_clk: DMA Axi4-lite interace clock
+ * @tx_clk: DMA mm2s clock
+ * @txs_clk: DMA mm2s stream clock
+ * @rx_clk: DMA s2mm clock
+ * @rxs_clk: DMA s2mm stream clock
+ * @nr_channels: Number of channels DMA device supports
+ * @chan_id: DMA channel identifier
+ */
+struct xilinx_dma_device {
+       void __iomem *regs;
+       struct device *dev;
+       struct dma_device common;
+       struct xilinx_dma_chan *chan[XILINX_DMA_MAX_CHANS_PER_DEVICE];
+       bool has_sg;
+       bool mcdma;
+       u32 flush_on_fsync;
+       bool ext_addr;
+       struct platform_device  *pdev;
+       const struct xilinx_dma_config *dma_config;
+       struct clk *axi_clk;
+       struct clk *tx_clk;
+       struct clk *txs_clk;
+       struct clk *rx_clk;
+       struct clk *rxs_clk;
+       u32 nr_channels;
+       u32 chan_id;
+};
+
+/* Macros */
+#define to_xilinx_chan(chan) \
+       container_of(chan, struct xilinx_dma_chan, common)
+#define to_dma_tx_descriptor(tx) \
+       container_of(tx, struct xilinx_dma_tx_descriptor, async_tx)
+#define xilinx_dma_poll_timeout(chan, reg, val, cond, delay_us, timeout_us) \
+       readl_poll_timeout(chan->xdev->regs + chan->ctrl_offset + reg, val, \
+                          cond, delay_us, timeout_us)
+
+/* IO accessors */
+static inline u32 dma_read(struct xilinx_dma_chan *chan, u32 reg)
+{
+       return ioread32(chan->xdev->regs + reg);
+}
+
+static inline void dma_write(struct xilinx_dma_chan *chan, u32 reg, u32 value)
+{
+       iowrite32(value, chan->xdev->regs + reg);
+}
+
+static inline void vdma_desc_write(struct xilinx_dma_chan *chan, u32 reg,
+                                  u32 value)
+{
+       dma_write(chan, chan->desc_offset + reg, value);
+}
+
+static inline u32 dma_ctrl_read(struct xilinx_dma_chan *chan, u32 reg)
+{
+       return dma_read(chan, chan->ctrl_offset + reg);
+}
+
+static inline void dma_ctrl_write(struct xilinx_dma_chan *chan, u32 reg,
+                                  u32 value)
+{
+       dma_write(chan, chan->ctrl_offset + reg, value);
+}
+
+static inline void dma_ctrl_clr(struct xilinx_dma_chan *chan, u32 reg,
+                                u32 clr)
+{
+       dma_ctrl_write(chan, reg, dma_ctrl_read(chan, reg) & ~clr);
+}
+
+static inline void dma_ctrl_set(struct xilinx_dma_chan *chan, u32 reg,
+                                u32 set)
+{
+       dma_ctrl_write(chan, reg, dma_ctrl_read(chan, reg) | set);
+}
+
+/**
+ * vdma_desc_write_64 - 64-bit descriptor write
+ * @chan: Driver specific VDMA channel
+ * @reg: Register to write
+ * @value_lsb: lower address of the descriptor.
+ * @value_msb: upper address of the descriptor.
+ *
+ * Since vdma driver is trying to write to a register offset which is not a
+ * multiple of 64 bits(ex : 0x5c), we are writing as two separate 32 bits
+ * instead of a single 64 bit register write.
+ */
+static inline void vdma_desc_write_64(struct xilinx_dma_chan *chan, u32 reg,
+                                     u32 value_lsb, u32 value_msb)
+{
+       /* Write the lsb 32 bits*/
+       writel(value_lsb, chan->xdev->regs + chan->desc_offset + reg);
+
+       /* Write the msb 32 bits */
+       writel(value_msb, chan->xdev->regs + chan->desc_offset + reg + 4);
+}
+
+static inline void dma_writeq(struct xilinx_dma_chan *chan, u32 reg, u64 value)
+{
+       lo_hi_writeq(value, chan->xdev->regs + chan->ctrl_offset + reg);
+}
+
+static inline void xilinx_write(struct xilinx_dma_chan *chan, u32 reg,
+                               dma_addr_t addr)
+{
+       if (chan->ext_addr)
+               dma_writeq(chan, reg, addr);
+       else
+               dma_ctrl_write(chan, reg, addr);
+}
+
+static inline void xilinx_axidma_buf(struct xilinx_dma_chan *chan,
+                                    struct xilinx_axidma_desc_hw *hw,
+                                    dma_addr_t buf_addr, size_t sg_used,
+                                    size_t period_len)
+{
+       if (chan->ext_addr) {
+               hw->buf_addr = lower_32_bits(buf_addr + sg_used + period_len);
+               hw->buf_addr_msb = upper_32_bits(buf_addr + sg_used +
+                                                period_len);
+       } else {
+               hw->buf_addr = buf_addr + sg_used + period_len;
+       }
+}
+
+/* -----------------------------------------------------------------------------
+ * Descriptors and segments alloc and free
+ */
+
+/**
+ * xilinx_vdma_alloc_tx_segment - Allocate transaction segment
+ * @chan: Driver specific DMA channel
+ *
+ * Return: The allocated segment on success and NULL on failure.
+ */
+static struct xilinx_vdma_tx_segment *
+xilinx_vdma_alloc_tx_segment(struct xilinx_dma_chan *chan)
+{
+       struct xilinx_vdma_tx_segment *segment;
+       dma_addr_t phys;
+
+       segment = dma_pool_zalloc(chan->desc_pool, GFP_ATOMIC, &phys);
+       if (!segment)
+               return NULL;
+
+       segment->phys = phys;
+
+       return segment;
+}
+
+/**
+ * xilinx_cdma_alloc_tx_segment - Allocate transaction segment
+ * @chan: Driver specific DMA channel
+ *
+ * Return: The allocated segment on success and NULL on failure.
+ */
+static struct xilinx_cdma_tx_segment *
+xilinx_cdma_alloc_tx_segment(struct xilinx_dma_chan *chan)
+{
+       struct xilinx_cdma_tx_segment *segment;
+       dma_addr_t phys;
+
+       segment = dma_pool_zalloc(chan->desc_pool, GFP_ATOMIC, &phys);
+       if (!segment)
+               return NULL;
+
+       segment->phys = phys;
+
+       return segment;
+}
+
+/**
+ * xilinx_axidma_alloc_tx_segment - Allocate transaction segment
+ * @chan: Driver specific DMA channel
+ *
+ * Return: The allocated segment on success and NULL on failure.
+ */
+static struct xilinx_axidma_tx_segment *
+xilinx_axidma_alloc_tx_segment(struct xilinx_dma_chan *chan)
+{
+       struct xilinx_axidma_tx_segment *segment;
+       dma_addr_t phys;
+
+       segment = dma_pool_zalloc(chan->desc_pool, GFP_ATOMIC, &phys);
+       if (!segment)
+               return NULL;
+
+       segment->phys = phys;
+
+       return segment;
+}
+
+/**
+ * xilinx_dma_free_tx_segment - Free transaction segment
+ * @chan: Driver specific DMA channel
+ * @segment: DMA transaction segment
+ */
+static void xilinx_dma_free_tx_segment(struct xilinx_dma_chan *chan,
+                               struct xilinx_axidma_tx_segment *segment)
+{
+       dma_pool_free(chan->desc_pool, segment, segment->phys);
+}
+
+/**
+ * xilinx_cdma_free_tx_segment - Free transaction segment
+ * @chan: Driver specific DMA channel
+ * @segment: DMA transaction segment
+ */
+static void xilinx_cdma_free_tx_segment(struct xilinx_dma_chan *chan,
+                               struct xilinx_cdma_tx_segment *segment)
+{
+       dma_pool_free(chan->desc_pool, segment, segment->phys);
+}
+
+/**
+ * xilinx_vdma_free_tx_segment - Free transaction segment
+ * @chan: Driver specific DMA channel
+ * @segment: DMA transaction segment
+ */
+static void xilinx_vdma_free_tx_segment(struct xilinx_dma_chan *chan,
+                                       struct xilinx_vdma_tx_segment *segment)
+{
+       dma_pool_free(chan->desc_pool, segment, segment->phys);
+}
+
+/**
+ * xilinx_dma_tx_descriptor - Allocate transaction descriptor
+ * @chan: Driver specific DMA channel
+ *
+ * Return: The allocated descriptor on success and NULL on failure.
+ */
+static struct xilinx_dma_tx_descriptor *
+xilinx_dma_alloc_tx_descriptor(struct xilinx_dma_chan *chan)
+{
+       struct xilinx_dma_tx_descriptor *desc;
+
+       desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+       if (!desc)
+               return NULL;
+
+       INIT_LIST_HEAD(&desc->segments);
+
+       return desc;
+}
+
+/**
+ * xilinx_dma_free_tx_descriptor - Free transaction descriptor
+ * @chan: Driver specific DMA channel
+ * @desc: DMA transaction descriptor
+ */
+static void
+xilinx_dma_free_tx_descriptor(struct xilinx_dma_chan *chan,
+                              struct xilinx_dma_tx_descriptor *desc)
+{
+       struct xilinx_vdma_tx_segment *segment, *next;
+       struct xilinx_cdma_tx_segment *cdma_segment, *cdma_next;
+       struct xilinx_axidma_tx_segment *axidma_segment, *axidma_next;
+
+       if (!desc)
+               return;
+
+       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
+               list_for_each_entry_safe(segment, next, &desc->segments, node) {
+                       list_del(&segment->node);
+                       xilinx_vdma_free_tx_segment(chan, segment);
+               }
+       } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
+               list_for_each_entry_safe(cdma_segment, cdma_next,
+                                        &desc->segments, node) {
+                       list_del(&cdma_segment->node);
+                       xilinx_cdma_free_tx_segment(chan, cdma_segment);
+               }
+       } else {
+               list_for_each_entry_safe(axidma_segment, axidma_next,
+                                        &desc->segments, node) {
+                       list_del(&axidma_segment->node);
+                       xilinx_dma_free_tx_segment(chan, axidma_segment);
+               }
+       }
+
+       kfree(desc);
+}
+
+/* Required functions */
+
+/**
+ * xilinx_dma_free_desc_list - Free descriptors list
+ * @chan: Driver specific DMA channel
+ * @list: List to parse and delete the descriptor
+ */
+static void xilinx_dma_free_desc_list(struct xilinx_dma_chan *chan,
+                                       struct list_head *list)
+{
+       struct xilinx_dma_tx_descriptor *desc, *next;
+
+       list_for_each_entry_safe(desc, next, list, node) {
+               list_del(&desc->node);
+               xilinx_dma_free_tx_descriptor(chan, desc);
+       }
+}
+
+/**
+ * xilinx_dma_free_descriptors - Free channel descriptors
+ * @chan: Driver specific DMA channel
+ */
+static void xilinx_dma_free_descriptors(struct xilinx_dma_chan *chan)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       xilinx_dma_free_desc_list(chan, &chan->pending_list);
+       xilinx_dma_free_desc_list(chan, &chan->done_list);
+       xilinx_dma_free_desc_list(chan, &chan->active_list);
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+/**
+ * xilinx_dma_free_chan_resources - Free channel resources
+ * @dchan: DMA channel
+ */
+static void xilinx_dma_free_chan_resources(struct dma_chan *dchan)
+{
+       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+
+       dev_dbg(chan->dev, "Free all channel resources.\n");
+
+       xilinx_dma_free_descriptors(chan);
+       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
+               xilinx_dma_free_tx_segment(chan, chan->cyclic_seg_v);
+               xilinx_dma_free_tx_segment(chan, chan->seg_v);
+       }
+       dma_pool_destroy(chan->desc_pool);
+       chan->desc_pool = NULL;
+}
+
+/**
+ * xilinx_dma_chan_handle_cyclic - Cyclic dma callback
+ * @chan: Driver specific dma channel
+ * @desc: dma transaction descriptor
+ * @flags: flags for spin lock
+ */
+static void xilinx_dma_chan_handle_cyclic(struct xilinx_dma_chan *chan,
+                                         struct xilinx_dma_tx_descriptor *desc,
+                                         unsigned long *flags)
+{
+       dma_async_tx_callback callback;
+       void *callback_param;
+
+       callback = desc->async_tx.callback;
+       callback_param = desc->async_tx.callback_param;
+       if (callback) {
+               spin_unlock_irqrestore(&chan->lock, *flags);
+               callback(callback_param);
+               spin_lock_irqsave(&chan->lock, *flags);
+       }
+}
+
+/**
+ * xilinx_dma_chan_desc_cleanup - Clean channel descriptors
+ * @chan: Driver specific DMA channel
+ */
+static void xilinx_dma_chan_desc_cleanup(struct xilinx_dma_chan *chan)
+{
+       struct xilinx_dma_tx_descriptor *desc, *next;
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       list_for_each_entry_safe(desc, next, &chan->done_list, node) {
+               dma_async_tx_callback callback;
+               void *callback_param;
+
+               if (desc->cyclic) {
+                       xilinx_dma_chan_handle_cyclic(chan, desc, &flags);
+                       break;
+               }
+
+               /* Remove from the list of running transactions */
+               list_del(&desc->node);
+
+               /* Run the link descriptor callback function */
+               callback = desc->async_tx.callback;
+               callback_param = desc->async_tx.callback_param;
+               if (callback) {
+                       spin_unlock_irqrestore(&chan->lock, flags);
+                       callback(callback_param);
+                       spin_lock_irqsave(&chan->lock, flags);
+               }
+
+               /* Run any dependencies, then free the descriptor */
+               dma_run_dependencies(&desc->async_tx);
+               xilinx_dma_free_tx_descriptor(chan, desc);
+       }
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+/**
+ * xilinx_dma_do_tasklet - Schedule completion tasklet
+ * @data: Pointer to the Xilinx DMA channel structure
+ */
+static void xilinx_dma_do_tasklet(unsigned long data)
+{
+       struct xilinx_dma_chan *chan = (struct xilinx_dma_chan *)data;
+
+       xilinx_dma_chan_desc_cleanup(chan);
+}
+
+/**
+ * xilinx_dma_alloc_chan_resources - Allocate channel resources
+ * @dchan: DMA channel
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan)
+{
+       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+
+       /* Has this channel already been allocated? */
+       if (chan->desc_pool)
+               return 0;
+
+       /*
+        * We need the descriptor to be aligned to 64bytes
+        * for meeting Xilinx VDMA specification requirement.
+        */
+       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
+               chan->desc_pool = dma_pool_create("xilinx_dma_desc_pool",
+                                  chan->dev,
+                                  sizeof(struct xilinx_axidma_tx_segment),
+                                  __alignof__(struct xilinx_axidma_tx_segment),
+                                  0);
+       } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
+               chan->desc_pool = dma_pool_create("xilinx_cdma_desc_pool",
+                                  chan->dev,
+                                  sizeof(struct xilinx_cdma_tx_segment),
+                                  __alignof__(struct xilinx_cdma_tx_segment),
+                                  0);
+       } else {
+               chan->desc_pool = dma_pool_create("xilinx_vdma_desc_pool",
+                                    chan->dev,
+                                    sizeof(struct xilinx_vdma_tx_segment),
+                                    __alignof__(struct xilinx_vdma_tx_segment),
+                                    0);
+       }
+
+       if (!chan->desc_pool) {
+               dev_err(chan->dev,
+                       "unable to allocate channel %d descriptor pool\n",
+                       chan->id);
+               return -ENOMEM;
+       }
+
+       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
+               /*
+                * For AXI DMA case after submitting a pending_list, keep
+                * an extra segment allocated so that the "next descriptor"
+                * pointer on the tail descriptor always points to a
+                * valid descriptor, even when paused after reaching taildesc.
+                * This way, it is possible to issue additional
+                * transfers without halting and restarting the channel.
+                */
+               chan->seg_v = xilinx_axidma_alloc_tx_segment(chan);
+
+               /*
+                * For cyclic DMA mode we need to program the tail Descriptor
+                * register with a value which is not a part of the BD chain
+                * so allocating a desc segment during channel allocation for
+                * programming tail descriptor.
+                */
+               chan->cyclic_seg_v = xilinx_axidma_alloc_tx_segment(chan);
+       }
+
+       dma_cookie_init(dchan);
+
+       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
+               /* For AXI DMA resetting once channel will reset the
+                * other channel as well so enable the interrupts here.
+                */
+               dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
+                             XILINX_DMA_DMAXR_ALL_IRQ_MASK);
+       }
+
+       if ((chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) && chan->has_sg)
+               dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
+                            XILINX_CDMA_CR_SGMODE);
+
+       return 0;
+}
+
+/**
+ * xilinx_dma_tx_status - Get DMA transaction status
+ * @dchan: DMA channel
+ * @cookie: Transaction identifier
+ * @txstate: Transaction state
+ *
+ * Return: DMA transaction status
+ */
+static enum dma_status xilinx_dma_tx_status(struct dma_chan *dchan,
+                                       dma_cookie_t cookie,
+                                       struct dma_tx_state *txstate)
+{
+       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+       struct xilinx_dma_tx_descriptor *desc;
+       struct xilinx_axidma_tx_segment *segment;
+       struct xilinx_axidma_desc_hw *hw;
+       enum dma_status ret;
+       unsigned long flags;
+       u32 residue = 0;
+
+       ret = dma_cookie_status(dchan, cookie, txstate);
+       if (ret == DMA_COMPLETE || !txstate)
+               return ret;
+
+       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
+               spin_lock_irqsave(&chan->lock, flags);
+
+               desc = list_last_entry(&chan->active_list,
+                                      struct xilinx_dma_tx_descriptor, node);
+               if (chan->has_sg) {
+                       list_for_each_entry(segment, &desc->segments, node) {
+                               hw = &segment->hw;
+                               residue += (hw->control - hw->status) &
+                                          XILINX_DMA_MAX_TRANS_LEN;
+                       }
+               }
+               spin_unlock_irqrestore(&chan->lock, flags);
+
+               chan->residue = residue;
+               dma_set_residue(txstate, chan->residue);
+       }
+
+       return ret;
+}
+
+/**
+ * xilinx_dma_is_running - Check if DMA channel is running
+ * @chan: Driver specific DMA channel
+ *
+ * Return: '1' if running, '0' if not.
+ */
+static bool xilinx_dma_is_running(struct xilinx_dma_chan *chan)
+{
+       return !(dma_ctrl_read(chan, XILINX_DMA_REG_DMASR) &
+                XILINX_DMA_DMASR_HALTED) &&
+               (dma_ctrl_read(chan, XILINX_DMA_REG_DMACR) &
+                XILINX_DMA_DMACR_RUNSTOP);
+}
+
+/**
+ * xilinx_dma_is_idle - Check if DMA channel is idle
+ * @chan: Driver specific DMA channel
+ *
+ * Return: '1' if idle, '0' if not.
+ */
+static bool xilinx_dma_is_idle(struct xilinx_dma_chan *chan)
+{
+       return dma_ctrl_read(chan, XILINX_DMA_REG_DMASR) &
+               XILINX_DMA_DMASR_IDLE;
+}
+
+/**
+ * xilinx_dma_halt - Halt DMA channel
+ * @chan: Driver specific DMA channel
+ */
+static void xilinx_dma_halt(struct xilinx_dma_chan *chan)
+{
+       int err;
+       u32 val;
+
+       dma_ctrl_clr(chan, XILINX_DMA_REG_DMACR, XILINX_DMA_DMACR_RUNSTOP);
+
+       /* Wait for the hardware to halt */
+       err = xilinx_dma_poll_timeout(chan, XILINX_DMA_REG_DMASR, val,
+                                     (val & XILINX_DMA_DMASR_HALTED), 0,
+                                     XILINX_DMA_LOOP_COUNT);
+
+       if (err) {
+               dev_err(chan->dev, "Cannot stop channel %p: %x\n",
+                       chan, dma_ctrl_read(chan, XILINX_DMA_REG_DMASR));
+               chan->err = true;
+       }
+}
+
+/**
+ * xilinx_dma_start - Start DMA channel
+ * @chan: Driver specific DMA channel
+ */
+static void xilinx_dma_start(struct xilinx_dma_chan *chan)
+{
+       int err;
+       u32 val;
+
+       dma_ctrl_set(chan, XILINX_DMA_REG_DMACR, XILINX_DMA_DMACR_RUNSTOP);
+
+       /* Wait for the hardware to start */
+       err = xilinx_dma_poll_timeout(chan, XILINX_DMA_REG_DMASR, val,
+                                     !(val & XILINX_DMA_DMASR_HALTED), 0,
+                                     XILINX_DMA_LOOP_COUNT);
+
+       if (err) {
+               dev_err(chan->dev, "Cannot start channel %p: %x\n",
+                       chan, dma_ctrl_read(chan, XILINX_DMA_REG_DMASR));
+
+               chan->err = true;
+       }
+}
+
+/**
+ * xilinx_vdma_start_transfer - Starts VDMA transfer
+ * @chan: Driver specific channel struct pointer
+ */
+static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan)
+{
+       struct xilinx_vdma_config *config = &chan->config;
+       struct xilinx_dma_tx_descriptor *desc, *tail_desc;
+       u32 reg;
+       struct xilinx_vdma_tx_segment *tail_segment;
+
+       /* This function was invoked with lock held */
+       if (chan->err)
+               return;
+
+       if (list_empty(&chan->pending_list))
+               return;
+
+       desc = list_first_entry(&chan->pending_list,
+                               struct xilinx_dma_tx_descriptor, node);
+       tail_desc = list_last_entry(&chan->pending_list,
+                                   struct xilinx_dma_tx_descriptor, node);
+
+       tail_segment = list_last_entry(&tail_desc->segments,
+                                      struct xilinx_vdma_tx_segment, node);
+
+       /* If it is SG mode and hardware is busy, cannot submit */
+       if (chan->has_sg && xilinx_dma_is_running(chan) &&
+           !xilinx_dma_is_idle(chan)) {
+               dev_dbg(chan->dev, "DMA controller still busy\n");
+               return;
+       }
+
+       /*
+        * If hardware is idle, then all descriptors on the running lists are
+        * done, start new transfers
+        */
+       if (chan->has_sg)
+               dma_ctrl_write(chan, XILINX_DMA_REG_CURDESC,
+                               desc->async_tx.phys);
+
+       /* Configure the hardware using info in the config structure */
+       reg = dma_ctrl_read(chan, XILINX_DMA_REG_DMACR);
+
+       if (config->frm_cnt_en)
+               reg |= XILINX_DMA_DMACR_FRAMECNT_EN;
+       else
+               reg &= ~XILINX_DMA_DMACR_FRAMECNT_EN;
+
+       /* Configure channel to allow number frame buffers */
+       dma_ctrl_write(chan, XILINX_DMA_REG_FRMSTORE,
+                       chan->desc_pendingcount);
+
+       /*
+        * With SG, start with circular mode, so that BDs can be fetched.
+        * In direct register mode, if not parking, enable circular mode
+        */
+       if (chan->has_sg || !config->park)
+               reg |= XILINX_DMA_DMACR_CIRC_EN;
+
+       if (config->park)
+               reg &= ~XILINX_DMA_DMACR_CIRC_EN;
+
+       dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
+
+       if (config->park && (config->park_frm >= 0) &&
+                       (config->park_frm < chan->num_frms)) {
+               if (chan->direction == DMA_MEM_TO_DEV)
+                       dma_write(chan, XILINX_DMA_REG_PARK_PTR,
+                               config->park_frm <<
+                                       XILINX_DMA_PARK_PTR_RD_REF_SHIFT);
+               else
+                       dma_write(chan, XILINX_DMA_REG_PARK_PTR,
+                               config->park_frm <<
+                                       XILINX_DMA_PARK_PTR_WR_REF_SHIFT);
+       }
+
+       /* Start the hardware */
+       xilinx_dma_start(chan);
+
+       if (chan->err)
+               return;
+
+       /* Start the transfer */
+       if (chan->has_sg) {
+               dma_ctrl_write(chan, XILINX_DMA_REG_TAILDESC,
+                               tail_segment->phys);
+       } else {
+               struct xilinx_vdma_tx_segment *segment, *last = NULL;
+               int i = 0;
+
+               if (chan->desc_submitcount < chan->num_frms)
+                       i = chan->desc_submitcount;
+
+               list_for_each_entry(segment, &desc->segments, node) {
+                       if (chan->ext_addr)
+                               vdma_desc_write_64(chan,
+                                       XILINX_VDMA_REG_START_ADDRESS_64(i++),
+                                       segment->hw.buf_addr,
+                                       segment->hw.buf_addr_msb);
+                       else
+                               vdma_desc_write(chan,
+                                       XILINX_VDMA_REG_START_ADDRESS(i++),
+                                       segment->hw.buf_addr);
+
+                       last = segment;
+               }
+
+               if (!last)
+                       return;
+
+               /* HW expects these parameters to be same for one transaction */
+               vdma_desc_write(chan, XILINX_DMA_REG_HSIZE, last->hw.hsize);
+               vdma_desc_write(chan, XILINX_DMA_REG_FRMDLY_STRIDE,
+                               last->hw.stride);
+               vdma_desc_write(chan, XILINX_DMA_REG_VSIZE, last->hw.vsize);
+       }
+
+       if (!chan->has_sg) {
+               list_del(&desc->node);
+               list_add_tail(&desc->node, &chan->active_list);
+               chan->desc_submitcount++;
+               chan->desc_pendingcount--;
+               if (chan->desc_submitcount == chan->num_frms)
+                       chan->desc_submitcount = 0;
+       } else {
+               list_splice_tail_init(&chan->pending_list, &chan->active_list);
+               chan->desc_pendingcount = 0;
+       }
+}
+
+/**
+ * xilinx_cdma_start_transfer - Starts cdma transfer
+ * @chan: Driver specific channel struct pointer
+ */
+static void xilinx_cdma_start_transfer(struct xilinx_dma_chan *chan)
+{
+       struct xilinx_dma_tx_descriptor *head_desc, *tail_desc;
+       struct xilinx_cdma_tx_segment *tail_segment;
+       u32 ctrl_reg = dma_read(chan, XILINX_DMA_REG_DMACR);
+
+       if (chan->err)
+               return;
+
+       if (list_empty(&chan->pending_list))
+               return;
+
+       head_desc = list_first_entry(&chan->pending_list,
+                                    struct xilinx_dma_tx_descriptor, node);
+       tail_desc = list_last_entry(&chan->pending_list,
+                                   struct xilinx_dma_tx_descriptor, node);
+       tail_segment = list_last_entry(&tail_desc->segments,
+                                      struct xilinx_cdma_tx_segment, node);
+
+       if (chan->desc_pendingcount <= XILINX_DMA_COALESCE_MAX) {
+               ctrl_reg &= ~XILINX_DMA_CR_COALESCE_MAX;
+               ctrl_reg |= chan->desc_pendingcount <<
+                               XILINX_DMA_CR_COALESCE_SHIFT;
+               dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, ctrl_reg);
+       }
+
+       if (chan->has_sg) {
+               xilinx_write(chan, XILINX_DMA_REG_CURDESC,
+                            head_desc->async_tx.phys);
+
+               /* Update tail ptr register which will start the transfer */
+               xilinx_write(chan, XILINX_DMA_REG_TAILDESC,
+                            tail_segment->phys);
+       } else {
+               /* In simple mode */
+               struct xilinx_cdma_tx_segment *segment;
+               struct xilinx_cdma_desc_hw *hw;
+
+               segment = list_first_entry(&head_desc->segments,
+                                          struct xilinx_cdma_tx_segment,
+                                          node);
+
+               hw = &segment->hw;
+
+               xilinx_write(chan, XILINX_CDMA_REG_SRCADDR, hw->src_addr);
+               xilinx_write(chan, XILINX_CDMA_REG_DSTADDR, hw->dest_addr);
+
+               /* Start the transfer */
+               dma_ctrl_write(chan, XILINX_DMA_REG_BTT,
+                               hw->control & XILINX_DMA_MAX_TRANS_LEN);
+       }
+
+       list_splice_tail_init(&chan->pending_list, &chan->active_list);
+       chan->desc_pendingcount = 0;
+}
+
+/**
+ * xilinx_dma_start_transfer - Starts DMA transfer
+ * @chan: Driver specific channel struct pointer
+ */
+static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
+{
+       struct xilinx_dma_tx_descriptor *head_desc, *tail_desc;
+       struct xilinx_axidma_tx_segment *tail_segment, *old_head, *new_head;
+       u32 reg;
+
+       if (chan->err)
+               return;
+
+       if (list_empty(&chan->pending_list))
+               return;
+
+       /* If it is SG mode and hardware is busy, cannot submit */
+       if (chan->has_sg && xilinx_dma_is_running(chan) &&
+           !xilinx_dma_is_idle(chan)) {
+               dev_dbg(chan->dev, "DMA controller still busy\n");
+               return;
+       }
+
+       head_desc = list_first_entry(&chan->pending_list,
+                                    struct xilinx_dma_tx_descriptor, node);
+       tail_desc = list_last_entry(&chan->pending_list,
+                                   struct xilinx_dma_tx_descriptor, node);
+       tail_segment = list_last_entry(&tail_desc->segments,
+                                      struct xilinx_axidma_tx_segment, node);
+
+       if (chan->has_sg && !chan->xdev->mcdma) {
+               old_head = list_first_entry(&head_desc->segments,
+                                       struct xilinx_axidma_tx_segment, node);
+               new_head = chan->seg_v;
+               /* Copy Buffer Descriptor fields. */
+               new_head->hw = old_head->hw;
+
+               /* Swap and save new reserve */
+               list_replace_init(&old_head->node, &new_head->node);
+               chan->seg_v = old_head;
+
+               tail_segment->hw.next_desc = chan->seg_v->phys;
+               head_desc->async_tx.phys = new_head->phys;
+       }
+
+       reg = dma_ctrl_read(chan, XILINX_DMA_REG_DMACR);
+
+       if (chan->desc_pendingcount <= XILINX_DMA_COALESCE_MAX) {
+               reg &= ~XILINX_DMA_CR_COALESCE_MAX;
+               reg |= chan->desc_pendingcount <<
+                                 XILINX_DMA_CR_COALESCE_SHIFT;
+               dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
+       }
+
+       if (chan->has_sg && !chan->xdev->mcdma)
+               xilinx_write(chan, XILINX_DMA_REG_CURDESC,
+                            head_desc->async_tx.phys);
+
+       if (chan->has_sg && chan->xdev->mcdma) {
+               if (chan->direction == DMA_MEM_TO_DEV) {
+                       dma_ctrl_write(chan, XILINX_DMA_REG_CURDESC,
+                                      head_desc->async_tx.phys);
+               } else {
+                       if (!chan->tdest) {
+                               dma_ctrl_write(chan, XILINX_DMA_REG_CURDESC,
+                                      head_desc->async_tx.phys);
+                       } else {
+                               dma_ctrl_write(chan,
+                                       XILINX_DMA_MCRX_CDESC(chan->tdest),
+                                      head_desc->async_tx.phys);
+                       }
+               }
+       }
+
+       xilinx_dma_start(chan);
+
+       if (chan->err)
+               return;
+
+       /* Start the transfer */
+       if (chan->has_sg && !chan->xdev->mcdma) {
+               if (chan->cyclic)
+                       xilinx_write(chan, XILINX_DMA_REG_TAILDESC,
+                                    chan->cyclic_seg_v->phys);
+               else
+                       xilinx_write(chan, XILINX_DMA_REG_TAILDESC,
+                                    tail_segment->phys);
+       } else if (chan->has_sg && chan->xdev->mcdma) {
+               if (chan->direction == DMA_MEM_TO_DEV) {
+                       dma_ctrl_write(chan, XILINX_DMA_REG_TAILDESC,
+                              tail_segment->phys);
+               } else {
+                       if (!chan->tdest) {
+                               dma_ctrl_write(chan, XILINX_DMA_REG_TAILDESC,
+                                              tail_segment->phys);
+                       } else {
+                               dma_ctrl_write(chan,
+                                       XILINX_DMA_MCRX_TDESC(chan->tdest),
+                                       tail_segment->phys);
+                       }
+               }
+       } else {
+               struct xilinx_axidma_tx_segment *segment;
+               struct xilinx_axidma_desc_hw *hw;
+
+               segment = list_first_entry(&head_desc->segments,
+                                          struct xilinx_axidma_tx_segment,
+                                          node);
+               hw = &segment->hw;
+
+               xilinx_write(chan, XILINX_DMA_REG_SRCDSTADDR, hw->buf_addr);
+
+               /* Start the transfer */
+               dma_ctrl_write(chan, XILINX_DMA_REG_BTT,
+                              hw->control & XILINX_DMA_MAX_TRANS_LEN);
+       }
+
+       list_splice_tail_init(&chan->pending_list, &chan->active_list);
+       chan->desc_pendingcount = 0;
+}
+
+/**
+ * xilinx_dma_issue_pending - Issue pending transactions
+ * @dchan: DMA channel
+ */
+static void xilinx_dma_issue_pending(struct dma_chan *dchan)
+{
+       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->lock, flags);
+       chan->start_transfer(chan);
+       spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+/**
+ * xilinx_dma_complete_descriptor - Mark the active descriptor as complete
+ * @chan : xilinx DMA channel
+ *
+ * CONTEXT: hardirq
+ */
+static void xilinx_dma_complete_descriptor(struct xilinx_dma_chan *chan)
+{
+       struct xilinx_dma_tx_descriptor *desc, *next;
+
+       /* This function was invoked with lock held */
+       if (list_empty(&chan->active_list))
+               return;
+
+       list_for_each_entry_safe(desc, next, &chan->active_list, node) {
+               list_del(&desc->node);
+               if (!desc->cyclic)
+                       dma_cookie_complete(&desc->async_tx);
+               list_add_tail(&desc->node, &chan->done_list);
+       }
+}
+
+/**
+ * xilinx_dma_reset - Reset DMA channel
+ * @chan: Driver specific DMA channel
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_dma_reset(struct xilinx_dma_chan *chan)
+{
+       int err;
+       u32 tmp;
+
+       dma_ctrl_set(chan, XILINX_DMA_REG_DMACR, XILINX_DMA_DMACR_RESET);
+
+       /* Wait for the hardware to finish reset */
+       err = xilinx_dma_poll_timeout(chan, XILINX_DMA_REG_DMACR, tmp,
+                                     !(tmp & XILINX_DMA_DMACR_RESET), 0,
+                                     XILINX_DMA_LOOP_COUNT);
+
+       if (err) {
+               dev_err(chan->dev, "reset timeout, cr %x, sr %x\n",
+                       dma_ctrl_read(chan, XILINX_DMA_REG_DMACR),
+                       dma_ctrl_read(chan, XILINX_DMA_REG_DMASR));
+               return -ETIMEDOUT;
+       }
+
+       chan->err = false;
+
+       return err;
+}
+
+/**
+ * xilinx_dma_chan_reset - Reset DMA channel and enable interrupts
+ * @chan: Driver specific DMA channel
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_dma_chan_reset(struct xilinx_dma_chan *chan)
+{
+       int err;
+
+       /* Reset VDMA */
+       err = xilinx_dma_reset(chan);
+       if (err)
+               return err;
+
+       /* Enable interrupts */
+       dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
+                     XILINX_DMA_DMAXR_ALL_IRQ_MASK);
+
+       return 0;
+}
+
+/**
+ * xilinx_dma_irq_handler - DMA Interrupt handler
+ * @irq: IRQ number
+ * @data: Pointer to the Xilinx DMA channel structure
+ *
+ * Return: IRQ_HANDLED/IRQ_NONE
+ */
+static irqreturn_t xilinx_dma_irq_handler(int irq, void *data)
+{
+       struct xilinx_dma_chan *chan = data;
+       u32 status;
+
+       /* Read the status and ack the interrupts. */
+       status = dma_ctrl_read(chan, XILINX_DMA_REG_DMASR);
+       if (!(status & XILINX_DMA_DMAXR_ALL_IRQ_MASK))
+               return IRQ_NONE;
+
+       dma_ctrl_write(chan, XILINX_DMA_REG_DMASR,
+                       status & XILINX_DMA_DMAXR_ALL_IRQ_MASK);
+
+       if (status & XILINX_DMA_DMASR_ERR_IRQ) {
+               /*
+                * An error occurred. If C_FLUSH_ON_FSYNC is enabled and the
+                * error is recoverable, ignore it. Otherwise flag the error.
+                *
+                * Only recoverable errors can be cleared in the DMASR register,
+                * make sure not to write to other error bits to 1.
+                */
+               u32 errors = status & XILINX_DMA_DMASR_ALL_ERR_MASK;
+
+               dma_ctrl_write(chan, XILINX_DMA_REG_DMASR,
+                               errors & XILINX_DMA_DMASR_ERR_RECOVER_MASK);
+
+               if (!chan->flush_on_fsync ||
+                   (errors & ~XILINX_DMA_DMASR_ERR_RECOVER_MASK)) {
+                       dev_err(chan->dev,
+                               "Channel %p has errors %x, cdr %x tdr %x\n",
+                               chan, errors,
+                               dma_ctrl_read(chan, XILINX_DMA_REG_CURDESC),
+                               dma_ctrl_read(chan, XILINX_DMA_REG_TAILDESC));
+                       chan->err = true;
+               }
+       }
+
+       if (status & XILINX_DMA_DMASR_DLY_CNT_IRQ) {
+               /*
+                * Device takes too long to do the transfer when user requires
+                * responsiveness.
+                */
+               dev_dbg(chan->dev, "Inter-packet latency too long\n");
+       }
+
+       if (status & XILINX_DMA_DMASR_FRM_CNT_IRQ) {
+               spin_lock(&chan->lock);
+               xilinx_dma_complete_descriptor(chan);
+               chan->start_transfer(chan);
+               spin_unlock(&chan->lock);
+       }
+
+       tasklet_schedule(&chan->tasklet);
+       return IRQ_HANDLED;
+}
+
+/**
+ * append_desc_queue - Queuing descriptor
+ * @chan: Driver specific dma channel
+ * @desc: dma transaction descriptor
+ */
+static void append_desc_queue(struct xilinx_dma_chan *chan,
+                             struct xilinx_dma_tx_descriptor *desc)
+{
+       struct xilinx_vdma_tx_segment *tail_segment;
+       struct xilinx_dma_tx_descriptor *tail_desc;
+       struct xilinx_axidma_tx_segment *axidma_tail_segment;
+       struct xilinx_cdma_tx_segment *cdma_tail_segment;
+
+       if (list_empty(&chan->pending_list))
+               goto append;
+
+       /*
+        * Add the hardware descriptor to the chain of hardware descriptors
+        * that already exists in memory.
+        */
+       tail_desc = list_last_entry(&chan->pending_list,
+                                   struct xilinx_dma_tx_descriptor, node);
+       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
+               tail_segment = list_last_entry(&tail_desc->segments,
+                                              struct xilinx_vdma_tx_segment,
+                                              node);
+               tail_segment->hw.next_desc = (u32)desc->async_tx.phys;
+       } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
+               cdma_tail_segment = list_last_entry(&tail_desc->segments,
+                                               struct xilinx_cdma_tx_segment,
+                                               node);
+               cdma_tail_segment->hw.next_desc = (u32)desc->async_tx.phys;
+       } else {
+               axidma_tail_segment = list_last_entry(&tail_desc->segments,
+                                              struct xilinx_axidma_tx_segment,
+                                              node);
+               axidma_tail_segment->hw.next_desc = (u32)desc->async_tx.phys;
+       }
+
+       /*
+        * Add the software descriptor and all children to the list
+        * of pending transactions
+        */
+append:
+       list_add_tail(&desc->node, &chan->pending_list);
+       chan->desc_pendingcount++;
+
+       if (chan->has_sg && (chan->xdev->dma_config->dmatype == XDMA_TYPE_VDMA)
+           && unlikely(chan->desc_pendingcount > chan->num_frms)) {
+               dev_dbg(chan->dev, "desc pendingcount is too high\n");
+               chan->desc_pendingcount = chan->num_frms;
+       }
+}
+
+/**
+ * xilinx_dma_tx_submit - Submit DMA transaction
+ * @tx: Async transaction descriptor
+ *
+ * Return: cookie value on success and failure value on error
+ */
+static dma_cookie_t xilinx_dma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+       struct xilinx_dma_tx_descriptor *desc = to_dma_tx_descriptor(tx);
+       struct xilinx_dma_chan *chan = to_xilinx_chan(tx->chan);
+       dma_cookie_t cookie;
+       unsigned long flags;
+       int err;
+
+       if (chan->cyclic) {
+               xilinx_dma_free_tx_descriptor(chan, desc);
+               return -EBUSY;
+       }
+
+       if (chan->err) {
+               /*
+                * If reset fails, need to hard reset the system.
+                * Channel is no longer functional
+                */
+               err = xilinx_dma_chan_reset(chan);
+               if (err < 0)
+                       return err;
+       }
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       cookie = dma_cookie_assign(tx);
+
+       /* Put this transaction onto the tail of the pending queue */
+       append_desc_queue(chan, desc);
+
+       if (desc->cyclic)
+               chan->cyclic = true;
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+
+       return cookie;
+}
+
+/**
+ * xilinx_vdma_dma_prep_interleaved - prepare a descriptor for a
+ *     DMA_SLAVE transaction
+ * @dchan: DMA channel
+ * @xt: Interleaved template pointer
+ * @flags: transfer ack flags
+ *
+ * Return: Async transaction descriptor on success and NULL on failure
+ */
+static struct dma_async_tx_descriptor *
+xilinx_vdma_dma_prep_interleaved(struct dma_chan *dchan,
+                                struct dma_interleaved_template *xt,
+                                unsigned long flags)
+{
+       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+       struct xilinx_dma_tx_descriptor *desc;
+       struct xilinx_vdma_tx_segment *segment, *prev = NULL;
+       struct xilinx_vdma_desc_hw *hw;
+
+       if (!is_slave_direction(xt->dir))
+               return NULL;
+
+       if (!xt->numf || !xt->sgl[0].size)
+               return NULL;
+
+       if (xt->frame_size != 1)
+               return NULL;
+
+       /* Allocate a transaction descriptor. */
+       desc = xilinx_dma_alloc_tx_descriptor(chan);
+       if (!desc)
+               return NULL;
+
+       dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
+       desc->async_tx.tx_submit = xilinx_dma_tx_submit;
+       async_tx_ack(&desc->async_tx);
+
+       /* Allocate the link descriptor from DMA pool */
+       segment = xilinx_vdma_alloc_tx_segment(chan);
+       if (!segment)
+               goto error;
+
+       /* Fill in the hardware descriptor */
+       hw = &segment->hw;
+       hw->vsize = xt->numf;
+       hw->hsize = xt->sgl[0].size;
+       hw->stride = (xt->sgl[0].icg + xt->sgl[0].size) <<
+                       XILINX_DMA_FRMDLY_STRIDE_STRIDE_SHIFT;
+       hw->stride |= chan->config.frm_dly <<
+                       XILINX_DMA_FRMDLY_STRIDE_FRMDLY_SHIFT;
+
+       if (xt->dir != DMA_MEM_TO_DEV) {
+               if (chan->ext_addr) {
+                       hw->buf_addr = lower_32_bits(xt->dst_start);
+                       hw->buf_addr_msb = upper_32_bits(xt->dst_start);
+               } else {
+                       hw->buf_addr = xt->dst_start;
+               }
+       } else {
+               if (chan->ext_addr) {
+                       hw->buf_addr = lower_32_bits(xt->src_start);
+                       hw->buf_addr_msb = upper_32_bits(xt->src_start);
+               } else {
+                       hw->buf_addr = xt->src_start;
+               }
+       }
+
+       /* Insert the segment into the descriptor segments list. */
+       list_add_tail(&segment->node, &desc->segments);
+
+       prev = segment;
+
+       /* Link the last hardware descriptor with the first. */
+       segment = list_first_entry(&desc->segments,
+                                  struct xilinx_vdma_tx_segment, node);
+       desc->async_tx.phys = segment->phys;
+
+       return &desc->async_tx;
+
+error:
+       xilinx_dma_free_tx_descriptor(chan, desc);
+       return NULL;
+}
+
+/**
+ * xilinx_cdma_prep_memcpy - prepare descriptors for a memcpy transaction
+ * @dchan: DMA channel
+ * @dma_dst: destination address
+ * @dma_src: source address
+ * @len: transfer length
+ * @flags: transfer ack flags
+ *
+ * Return: Async transaction descriptor on success and NULL on failure
+ */
+static struct dma_async_tx_descriptor *
+xilinx_cdma_prep_memcpy(struct dma_chan *dchan, dma_addr_t dma_dst,
+                       dma_addr_t dma_src, size_t len, unsigned long flags)
+{
+       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+       struct xilinx_dma_tx_descriptor *desc;
+       struct xilinx_cdma_tx_segment *segment, *prev;
+       struct xilinx_cdma_desc_hw *hw;
+
+       if (!len || len > XILINX_DMA_MAX_TRANS_LEN)
+               return NULL;
+
+       desc = xilinx_dma_alloc_tx_descriptor(chan);
+       if (!desc)
+               return NULL;
+
+       dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
+       desc->async_tx.tx_submit = xilinx_dma_tx_submit;
+
+       /* Allocate the link descriptor from DMA pool */
+       segment = xilinx_cdma_alloc_tx_segment(chan);
+       if (!segment)
+               goto error;
+
+       hw = &segment->hw;
+       hw->control = len;
+       hw->src_addr = dma_src;
+       hw->dest_addr = dma_dst;
+       if (chan->ext_addr) {
+               hw->src_addr_msb = upper_32_bits(dma_src);
+               hw->dest_addr_msb = upper_32_bits(dma_dst);
+       }
+
+       /* Fill the previous next descriptor with current */
+       prev = list_last_entry(&desc->segments,
+                              struct xilinx_cdma_tx_segment, node);
+       prev->hw.next_desc = segment->phys;
+
+       /* Insert the segment into the descriptor segments list. */
+       list_add_tail(&segment->node, &desc->segments);
+
+       prev = segment;
+
+       /* Link the last hardware descriptor with the first. */
+       segment = list_first_entry(&desc->segments,
+                               struct xilinx_cdma_tx_segment, node);
+       desc->async_tx.phys = segment->phys;
+       prev->hw.next_desc = segment->phys;
+
+       return &desc->async_tx;
+
+error:
+       xilinx_dma_free_tx_descriptor(chan, desc);
+       return NULL;
+}
+
+/**
+ * xilinx_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
+ * @dchan: DMA channel
+ * @sgl: scatterlist to transfer to/from
+ * @sg_len: number of entries in @scatterlist
+ * @direction: DMA direction
+ * @flags: transfer ack flags
+ * @context: APP words of the descriptor
+ *
+ * Return: Async transaction descriptor on success and NULL on failure
+ */
+static struct dma_async_tx_descriptor *xilinx_dma_prep_slave_sg(
+       struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len,
+       enum dma_transfer_direction direction, unsigned long flags,
+       void *context)
+{
+       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+       struct xilinx_dma_tx_descriptor *desc;
+       struct xilinx_axidma_tx_segment *segment = NULL, *prev = NULL;
+       u32 *app_w = (u32 *)context;
+       struct scatterlist *sg;
+       size_t copy;
+       size_t sg_used;
+       unsigned int i;
+
+       if (!is_slave_direction(direction))
+               return NULL;
+
+       /* Allocate a transaction descriptor. */
+       desc = xilinx_dma_alloc_tx_descriptor(chan);
+       if (!desc)
+               return NULL;
+
+       dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
+       desc->async_tx.tx_submit = xilinx_dma_tx_submit;
+
+       /* Build transactions using information in the scatter gather list */
+       for_each_sg(sgl, sg, sg_len, i) {
+               sg_used = 0;
+
+               /* Loop until the entire scatterlist entry is used */
+               while (sg_used < sg_dma_len(sg)) {
+                       struct xilinx_axidma_desc_hw *hw;
+
+                       /* Get a free segment */
+                       segment = xilinx_axidma_alloc_tx_segment(chan);
+                       if (!segment)
+                               goto error;
+
+                       /*
+                        * Calculate the maximum number of bytes to transfer,
+                        * making sure it is less than the hw limit
+                        */
+                       copy = min_t(size_t, sg_dma_len(sg) - sg_used,
+                                    XILINX_DMA_MAX_TRANS_LEN);
+                       hw = &segment->hw;
+
+                       /* Fill in the descriptor */
+                       xilinx_axidma_buf(chan, hw, sg_dma_address(sg),
+                                         sg_used, 0);
+
+                       hw->control = copy;
+
+                       if (chan->direction == DMA_MEM_TO_DEV) {
+                               if (app_w)
+                                       memcpy(hw->app, app_w, sizeof(u32) *
+                                              XILINX_DMA_NUM_APP_WORDS);
+                       }
+
+                       if (prev)
+                               prev->hw.next_desc = segment->phys;
+
+                       prev = segment;
+                       sg_used += copy;
+
+                       /*
+                        * Insert the segment into the descriptor segments
+                        * list.
+                        */
+                       list_add_tail(&segment->node, &desc->segments);
+               }
+       }
+
+       segment = list_first_entry(&desc->segments,
+                                  struct xilinx_axidma_tx_segment, node);
+       desc->async_tx.phys = segment->phys;
+       prev->hw.next_desc = segment->phys;
+
+       /* For the last DMA_MEM_TO_DEV transfer, set EOP */
+       if (chan->direction == DMA_MEM_TO_DEV) {
+               segment->hw.control |= XILINX_DMA_BD_SOP;
+               segment = list_last_entry(&desc->segments,
+                                         struct xilinx_axidma_tx_segment,
+                                         node);
+               segment->hw.control |= XILINX_DMA_BD_EOP;
+       }
+
+       return &desc->async_tx;
+
+error:
+       xilinx_dma_free_tx_descriptor(chan, desc);
+       return NULL;
+}
+
+/**
+ * xilinx_dma_prep_dma_cyclic - prepare descriptors for a DMA_SLAVE transaction
+ * @chan: DMA channel
+ * @sgl: scatterlist to transfer to/from
+ * @sg_len: number of entries in @scatterlist
+ * @direction: DMA direction
+ * @flags: transfer ack flags
+ */
+static struct dma_async_tx_descriptor *xilinx_dma_prep_dma_cyclic(
+       struct dma_chan *dchan, dma_addr_t buf_addr, size_t buf_len,
+       size_t period_len, enum dma_transfer_direction direction,
+       unsigned long flags)
+{
+       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+       struct xilinx_dma_tx_descriptor *desc;
+       struct xilinx_axidma_tx_segment *segment, *head_segment, *prev = NULL;
+       size_t copy, sg_used;
+       unsigned int num_periods;
+       int i;
+       u32 reg;
+
+       if (!period_len)
+               return NULL;
+
+       num_periods = buf_len / period_len;
+
+       if (!num_periods)
+               return NULL;
+
+       if (!is_slave_direction(direction))
+               return NULL;
+
+       /* Allocate a transaction descriptor. */
+       desc = xilinx_dma_alloc_tx_descriptor(chan);
+       if (!desc)
+               return NULL;
+
+       chan->direction = direction;
+       dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
+       desc->async_tx.tx_submit = xilinx_dma_tx_submit;
+
+       for (i = 0; i < num_periods; ++i) {
+               sg_used = 0;
+
+               while (sg_used < period_len) {
+                       struct xilinx_axidma_desc_hw *hw;
+
+                       /* Get a free segment */
+                       segment = xilinx_axidma_alloc_tx_segment(chan);
+                       if (!segment)
+                               goto error;
+
+                       /*
+                        * Calculate the maximum number of bytes to transfer,
+                        * making sure it is less than the hw limit
+                        */
+                       copy = min_t(size_t, period_len - sg_used,
+                                    XILINX_DMA_MAX_TRANS_LEN);
+                       hw = &segment->hw;
+                       xilinx_axidma_buf(chan, hw, buf_addr, sg_used,
+                                         period_len * i);
+                       hw->control = copy;
+
+                       if (prev)
+                               prev->hw.next_desc = segment->phys;
+
+                       prev = segment;
+                       sg_used += copy;
+
+                       /*
+                        * Insert the segment into the descriptor segments
+                        * list.
+                        */
+                       list_add_tail(&segment->node, &desc->segments);
+               }
+       }
+
+       head_segment = list_first_entry(&desc->segments,
+                                  struct xilinx_axidma_tx_segment, node);
+       desc->async_tx.phys = head_segment->phys;
+
+       desc->cyclic = true;
+       reg = dma_ctrl_read(chan, XILINX_DMA_REG_DMACR);
+       reg |= XILINX_DMA_CR_CYCLIC_BD_EN_MASK;
+       dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
+
+       segment = list_last_entry(&desc->segments,
+                                 struct xilinx_axidma_tx_segment,
+                                 node);
+       segment->hw.next_desc = (u32) head_segment->phys;
+
+       /* For the last DMA_MEM_TO_DEV transfer, set EOP */
+       if (direction == DMA_MEM_TO_DEV) {
+               head_segment->hw.control |= XILINX_DMA_BD_SOP;
+               segment->hw.control |= XILINX_DMA_BD_EOP;
+       }
+
+       return &desc->async_tx;
+
+error:
+       xilinx_dma_free_tx_descriptor(chan, desc);
+       return NULL;
+}
+
+/**
+ * xilinx_dma_prep_interleaved - prepare a descriptor for a
+ *     DMA_SLAVE transaction
+ * @dchan: DMA channel
+ * @xt: Interleaved template pointer
+ * @flags: transfer ack flags
+ *
+ * Return: Async transaction descriptor on success and NULL on failure
+ */
+static struct dma_async_tx_descriptor *
+xilinx_dma_prep_interleaved(struct dma_chan *dchan,
+                                struct dma_interleaved_template *xt,
+                                unsigned long flags)
+{
+       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+       struct xilinx_dma_tx_descriptor *desc;
+       struct xilinx_axidma_tx_segment *segment;
+       struct xilinx_axidma_desc_hw *hw;
+
+       if (!is_slave_direction(xt->dir))
+               return NULL;
+
+       if (!xt->numf || !xt->sgl[0].size)
+               return NULL;
+
+       if (xt->frame_size != 1)
+               return NULL;
+
+       /* Allocate a transaction descriptor. */
+       desc = xilinx_dma_alloc_tx_descriptor(chan);
+       if (!desc)
+               return NULL;
+
+       chan->direction = xt->dir;
+       dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
+       desc->async_tx.tx_submit = xilinx_dma_tx_submit;
+
+       /* Get a free segment */
+       segment = xilinx_axidma_alloc_tx_segment(chan);
+       if (!segment)
+               goto error;
+
+       hw = &segment->hw;
+
+       /* Fill in the descriptor */
+       if (xt->dir != DMA_MEM_TO_DEV)
+               hw->buf_addr = xt->dst_start;
+       else
+               hw->buf_addr = xt->src_start;
+
+       hw->mcdma_control = chan->tdest & XILINX_DMA_BD_TDEST_MASK;
+       hw->vsize_stride = (xt->numf << XILINX_DMA_BD_VSIZE_SHIFT) &
+                           XILINX_DMA_BD_VSIZE_MASK;
+       hw->vsize_stride |= (xt->sgl[0].icg + xt->sgl[0].size) &
+                           XILINX_DMA_BD_STRIDE_MASK;
+       hw->control = xt->sgl[0].size & XILINX_DMA_BD_HSIZE_MASK;
+
+       /*
+        * Insert the segment into the descriptor segments
+        * list.
+        */
+       list_add_tail(&segment->node, &desc->segments);
+
+
+       segment = list_first_entry(&desc->segments,
+                                  struct xilinx_axidma_tx_segment, node);
+       desc->async_tx.phys = segment->phys;
+
+       /* For the last DMA_MEM_TO_DEV transfer, set EOP */
+       if (xt->dir == DMA_MEM_TO_DEV) {
+               segment->hw.control |= XILINX_DMA_BD_SOP;
+               segment = list_last_entry(&desc->segments,
+                                         struct xilinx_axidma_tx_segment,
+                                         node);
+               segment->hw.control |= XILINX_DMA_BD_EOP;
+       }
+
+       return &desc->async_tx;
+
+error:
+       xilinx_dma_free_tx_descriptor(chan, desc);
+       return NULL;
+}
+
+/**
+ * xilinx_dma_terminate_all - Halt the channel and free descriptors
+ * @chan: Driver specific DMA Channel pointer
+ */
+static int xilinx_dma_terminate_all(struct dma_chan *dchan)
+{
+       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+       u32 reg;
+
+       if (chan->cyclic)
+               xilinx_dma_chan_reset(chan);
+
+       /* Halt the DMA engine */
+       xilinx_dma_halt(chan);
+
+       /* Remove and free all of the descriptors in the lists */
+       xilinx_dma_free_descriptors(chan);
+
+       if (chan->cyclic) {
+               reg = dma_ctrl_read(chan, XILINX_DMA_REG_DMACR);
+               reg &= ~XILINX_DMA_CR_CYCLIC_BD_EN_MASK;
+               dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
+               chan->cyclic = false;
+       }
+
+       return 0;
+}
+
+/**
+ * xilinx_dma_channel_set_config - Configure VDMA channel
+ * Run-time configuration for Axi VDMA, supports:
+ * . halt the channel
+ * . configure interrupt coalescing and inter-packet delay threshold
+ * . start/stop parking
+ * . enable genlock
+ *
+ * @dchan: DMA channel
+ * @cfg: VDMA device configuration pointer
+ *
+ * Return: '0' on success and failure value on error
+ */
+int xilinx_vdma_channel_set_config(struct dma_chan *dchan,
+                                       struct xilinx_vdma_config *cfg)
+{
+       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+       u32 dmacr;
+
+       if (cfg->reset)
+               return xilinx_dma_chan_reset(chan);
+
+       dmacr = dma_ctrl_read(chan, XILINX_DMA_REG_DMACR);
+
+       chan->config.frm_dly = cfg->frm_dly;
+       chan->config.park = cfg->park;
+
+       /* genlock settings */
+       chan->config.gen_lock = cfg->gen_lock;
+       chan->config.master = cfg->master;
+
+       if (cfg->gen_lock && chan->genlock) {
+               dmacr |= XILINX_DMA_DMACR_GENLOCK_EN;
+               dmacr |= cfg->master << XILINX_DMA_DMACR_MASTER_SHIFT;
+       }
+
+       chan->config.frm_cnt_en = cfg->frm_cnt_en;
+       if (cfg->park)
+               chan->config.park_frm = cfg->park_frm;
+       else
+               chan->config.park_frm = -1;
+
+       chan->config.coalesc = cfg->coalesc;
+       chan->config.delay = cfg->delay;
+
+       if (cfg->coalesc <= XILINX_DMA_DMACR_FRAME_COUNT_MAX) {
+               dmacr |= cfg->coalesc << XILINX_DMA_DMACR_FRAME_COUNT_SHIFT;
+               chan->config.coalesc = cfg->coalesc;
+       }
+
+       if (cfg->delay <= XILINX_DMA_DMACR_DELAY_MAX) {
+               dmacr |= cfg->delay << XILINX_DMA_DMACR_DELAY_SHIFT;
+               chan->config.delay = cfg->delay;
+       }
+
+       /* FSync Source selection */
+       dmacr &= ~XILINX_DMA_DMACR_FSYNCSRC_MASK;
+       dmacr |= cfg->ext_fsync << XILINX_DMA_DMACR_FSYNCSRC_SHIFT;
+
+       dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, dmacr);
+
+       return 0;
+}
+EXPORT_SYMBOL(xilinx_vdma_channel_set_config);
+
+/* -----------------------------------------------------------------------------
+ * Probe and remove
+ */
+
+/**
+ * xilinx_dma_chan_remove - Per Channel remove function
+ * @chan: Driver specific DMA channel
+ */
+static void xilinx_dma_chan_remove(struct xilinx_dma_chan *chan)
+{
+       /* Disable all interrupts */
+       dma_ctrl_clr(chan, XILINX_DMA_REG_DMACR,
+                     XILINX_DMA_DMAXR_ALL_IRQ_MASK);
+
+       if (chan->irq > 0)
+               free_irq(chan->irq, chan);
+
+       tasklet_kill(&chan->tasklet);
+
+       list_del(&chan->common.device_node);
+}
+
+static int axidma_clk_init(struct platform_device *pdev, struct clk **axi_clk,
+                           struct clk **tx_clk, struct clk **rx_clk,
+                           struct clk **sg_clk, struct clk **tmp_clk)
+{
+       int err;
+
+       *tmp_clk = NULL;
+
+       *axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk");
+       if (IS_ERR(*axi_clk)) {
+               err = PTR_ERR(*axi_clk);
+               dev_err(&pdev->dev, "failed to get axi_aclk (%u)\n", err);
+               return err;
+       }
+
+       *tx_clk = devm_clk_get(&pdev->dev, "m_axi_mm2s_aclk");
+       if (IS_ERR(*tx_clk))
+               *tx_clk = NULL;
+
+       *rx_clk = devm_clk_get(&pdev->dev, "m_axi_s2mm_aclk");
+       if (IS_ERR(*rx_clk))
+               *rx_clk = NULL;
+
+       *sg_clk = devm_clk_get(&pdev->dev, "m_axi_sg_aclk");
+       if (IS_ERR(*sg_clk))
+               *sg_clk = NULL;
+
+       err = clk_prepare_enable(*axi_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err);
+               return err;
+       }
+
+       err = clk_prepare_enable(*tx_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err);
+               goto err_disable_axiclk;
+       }
+
+       err = clk_prepare_enable(*rx_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable rx_clk (%u)\n", err);
+               goto err_disable_txclk;
+       }
+
+       err = clk_prepare_enable(*sg_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable sg_clk (%u)\n", err);
+               goto err_disable_rxclk;
+       }
+
+       return 0;
+
+err_disable_rxclk:
+       clk_disable_unprepare(*rx_clk);
+err_disable_txclk:
+       clk_disable_unprepare(*tx_clk);
+err_disable_axiclk:
+       clk_disable_unprepare(*axi_clk);
+
+       return err;
+}
+
+static int axicdma_clk_init(struct platform_device *pdev, struct clk **axi_clk,
+                           struct clk **dev_clk, struct clk **tmp_clk,
+                           struct clk **tmp1_clk, struct clk **tmp2_clk)
+{
+       int err;
+
+       *tmp_clk = NULL;
+       *tmp1_clk = NULL;
+       *tmp2_clk = NULL;
+
+       *axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk");
+       if (IS_ERR(*axi_clk)) {
+               err = PTR_ERR(*axi_clk);
+               dev_err(&pdev->dev, "failed to get axi_clk (%u)\n", err);
+               return err;
+       }
+
+       *dev_clk = devm_clk_get(&pdev->dev, "m_axi_aclk");
+       if (IS_ERR(*dev_clk)) {
+               err = PTR_ERR(*dev_clk);
+               dev_err(&pdev->dev, "failed to get dev_clk (%u)\n", err);
+               return err;
+       }
+
+       err = clk_prepare_enable(*axi_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err);
+               return err;
+       }
+
+       err = clk_prepare_enable(*dev_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable dev_clk (%u)\n", err);
+               goto err_disable_axiclk;
+       }
+
+       return 0;
+
+err_disable_axiclk:
+       clk_disable_unprepare(*axi_clk);
+
+       return err;
+}
+
+static int axivdma_clk_init(struct platform_device *pdev, struct clk **axi_clk,
+                           struct clk **tx_clk, struct clk **txs_clk,
+                           struct clk **rx_clk, struct clk **rxs_clk)
+{
+       int err;
+
+       *axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk");
+       if (IS_ERR(*axi_clk)) {
+               err = PTR_ERR(*axi_clk);
+               dev_err(&pdev->dev, "failed to get axi_aclk (%u)\n", err);
+               return err;
+       }
+
+       *tx_clk = devm_clk_get(&pdev->dev, "m_axi_mm2s_aclk");
+       if (IS_ERR(*tx_clk))
+               *tx_clk = NULL;
+
+       *txs_clk = devm_clk_get(&pdev->dev, "m_axis_mm2s_aclk");
+       if (IS_ERR(*txs_clk))
+               *txs_clk = NULL;
+
+       *rx_clk = devm_clk_get(&pdev->dev, "m_axi_s2mm_aclk");
+       if (IS_ERR(*rx_clk))
+               *rx_clk = NULL;
+
+       *rxs_clk = devm_clk_get(&pdev->dev, "s_axis_s2mm_aclk");
+       if (IS_ERR(*rxs_clk))
+               *rxs_clk = NULL;
+
+       err = clk_prepare_enable(*axi_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err);
+               return err;
+       }
+
+       err = clk_prepare_enable(*tx_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err);
+               goto err_disable_axiclk;
+       }
+
+       err = clk_prepare_enable(*txs_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable txs_clk (%u)\n", err);
+               goto err_disable_txclk;
+       }
+
+       err = clk_prepare_enable(*rx_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable rx_clk (%u)\n", err);
+               goto err_disable_txsclk;
+       }
+
+       err = clk_prepare_enable(*rxs_clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable rxs_clk (%u)\n", err);
+               goto err_disable_rxclk;
+       }
+
+       return 0;
+
+err_disable_rxclk:
+       clk_disable_unprepare(*rx_clk);
+err_disable_txsclk:
+       clk_disable_unprepare(*txs_clk);
+err_disable_txclk:
+       clk_disable_unprepare(*tx_clk);
+err_disable_axiclk:
+       clk_disable_unprepare(*axi_clk);
+
+       return err;
+}
+
+static void xdma_disable_allclks(struct xilinx_dma_device *xdev)
+{
+       clk_disable_unprepare(xdev->rxs_clk);
+       clk_disable_unprepare(xdev->rx_clk);
+       clk_disable_unprepare(xdev->txs_clk);
+       clk_disable_unprepare(xdev->tx_clk);
+       clk_disable_unprepare(xdev->axi_clk);
+}
+
+/**
+ * xilinx_dma_chan_probe - Per Channel Probing
+ * It get channel features from the device tree entry and
+ * initialize special channel handling routines
+ *
+ * @xdev: Driver specific device structure
+ * @node: Device node
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
+                                 struct device_node *node, int chan_id)
+{
+       struct xilinx_dma_chan *chan;
+       bool has_dre = false;
+       u32 value, width;
+       int err;
+
+       /* Allocate and initialize the channel structure */
+       chan = devm_kzalloc(xdev->dev, sizeof(*chan), GFP_KERNEL);
+       if (!chan)
+               return -ENOMEM;
+
+       chan->dev = xdev->dev;
+       chan->xdev = xdev;
+       chan->has_sg = xdev->has_sg;
+       chan->desc_pendingcount = 0x0;
+       chan->ext_addr = xdev->ext_addr;
+
+       spin_lock_init(&chan->lock);
+       INIT_LIST_HEAD(&chan->pending_list);
+       INIT_LIST_HEAD(&chan->done_list);
+       INIT_LIST_HEAD(&chan->active_list);
+
+       /* Retrieve the channel properties from the device tree */
+       has_dre = of_property_read_bool(node, "xlnx,include-dre");
+
+       chan->genlock = of_property_read_bool(node, "xlnx,genlock-mode");
+
+       err = of_property_read_u32(node, "xlnx,datawidth", &value);
+       if (err) {
+               dev_err(xdev->dev, "missing xlnx,datawidth property\n");
+               return err;
+       }
+       width = value >> 3; /* Convert bits to bytes */
+
+       /* If data width is greater than 8 bytes, DRE is not in hw */
+       if (width > 8)
+               has_dre = false;
+
+       if (!has_dre)
+               xdev->common.copy_align = fls(width - 1);
+
+       if (of_device_is_compatible(node, "xlnx,axi-vdma-mm2s-channel") ||
+           of_device_is_compatible(node, "xlnx,axi-dma-mm2s-channel") ||
+           of_device_is_compatible(node, "xlnx,axi-cdma-channel")) {
+               chan->direction = DMA_MEM_TO_DEV;
+               chan->id = chan_id;
+               chan->tdest = chan_id;
+
+               chan->ctrl_offset = XILINX_DMA_MM2S_CTRL_OFFSET;
+               if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
+                       chan->desc_offset = XILINX_VDMA_MM2S_DESC_OFFSET;
+
+                       if (xdev->flush_on_fsync == XILINX_DMA_FLUSH_BOTH ||
+                           xdev->flush_on_fsync == XILINX_DMA_FLUSH_MM2S)
+                               chan->flush_on_fsync = true;
+               }
+       } else if (of_device_is_compatible(node,
+                                          "xlnx,axi-vdma-s2mm-channel") ||
+                  of_device_is_compatible(node,
+                                          "xlnx,axi-dma-s2mm-channel")) {
+               chan->direction = DMA_DEV_TO_MEM;
+               chan->id = chan_id;
+               chan->tdest = chan_id - xdev->nr_channels;
+
+               chan->ctrl_offset = XILINX_DMA_S2MM_CTRL_OFFSET;
+               if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
+                       chan->desc_offset = XILINX_VDMA_S2MM_DESC_OFFSET;
+
+                       if (xdev->flush_on_fsync == XILINX_DMA_FLUSH_BOTH ||
+                           xdev->flush_on_fsync == XILINX_DMA_FLUSH_S2MM)
+                               chan->flush_on_fsync = true;
+               }
+       } else {
+               dev_err(xdev->dev, "Invalid channel compatible node\n");
+               return -EINVAL;
+       }
+
+       /* Request the interrupt */
+       chan->irq = irq_of_parse_and_map(node, 0);
+       err = request_irq(chan->irq, xilinx_dma_irq_handler, IRQF_SHARED,
+                         "xilinx-dma-controller", chan);
+       if (err) {
+               dev_err(xdev->dev, "unable to request IRQ %d\n", chan->irq);
+               return err;
+       }
+
+       if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA)
+               chan->start_transfer = xilinx_dma_start_transfer;
+       else if (xdev->dma_config->dmatype == XDMA_TYPE_CDMA)
+               chan->start_transfer = xilinx_cdma_start_transfer;
+       else
+               chan->start_transfer = xilinx_vdma_start_transfer;
+
+       /* Initialize the tasklet */
+       tasklet_init(&chan->tasklet, xilinx_dma_do_tasklet,
+                       (unsigned long)chan);
+
+       /*
+        * Initialize the DMA channel and add it to the DMA engine channels
+        * list.
+        */
+       chan->common.device = &xdev->common;
+
+       list_add_tail(&chan->common.device_node, &xdev->common.channels);
+       xdev->chan[chan->id] = chan;
+
+       /* Reset the channel */
+       err = xilinx_dma_chan_reset(chan);
+       if (err < 0) {
+               dev_err(xdev->dev, "Reset channel failed\n");
+               return err;
+       }
+
+       return 0;
+}
+
+/**
+ * xilinx_dma_child_probe - Per child node probe
+ * It get number of dma-channels per child node from
+ * device-tree and initializes all the channels.
+ *
+ * @xdev: Driver specific device structure
+ * @node: Device node
+ *
+ * Return: 0 always.
+ */
+static int xilinx_dma_child_probe(struct xilinx_dma_device *xdev,
+                                   struct device_node *node) {
+       int ret, i, nr_channels = 1;
+
+       ret = of_property_read_u32(node, "dma-channels", &nr_channels);
+       if ((ret < 0) && xdev->mcdma)
+               dev_warn(xdev->dev, "missing dma-channels property\n");
+
+       for (i = 0; i < nr_channels; i++)
+               xilinx_dma_chan_probe(xdev, node, xdev->chan_id++);
+
+       xdev->nr_channels += nr_channels;
+
+       return 0;
+}
+
+/**
+ * of_dma_xilinx_xlate - Translation function
+ * @dma_spec: Pointer to DMA specifier as found in the device tree
+ * @ofdma: Pointer to DMA controller data
+ *
+ * Return: DMA channel pointer on success and NULL on error
+ */
+static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec,
+                                               struct of_dma *ofdma)
+{
+       struct xilinx_dma_device *xdev = ofdma->of_dma_data;
+       int chan_id = dma_spec->args[0];
+
+       if (chan_id >= xdev->nr_channels || !xdev->chan[chan_id])
+               return NULL;
+
+       return dma_get_slave_channel(&xdev->chan[chan_id]->common);
+}
+
+static const struct xilinx_dma_config axidma_config = {
+       .dmatype = XDMA_TYPE_AXIDMA,
+       .clk_init = axidma_clk_init,
+};
+
+static const struct xilinx_dma_config axicdma_config = {
+       .dmatype = XDMA_TYPE_CDMA,
+       .clk_init = axicdma_clk_init,
+};
+
+static const struct xilinx_dma_config axivdma_config = {
+       .dmatype = XDMA_TYPE_VDMA,
+       .clk_init = axivdma_clk_init,
+};
+
+static const struct of_device_id xilinx_dma_of_ids[] = {
+       { .compatible = "xlnx,axi-dma-1.00.a", .data = &axidma_config },
+       { .compatible = "xlnx,axi-cdma-1.00.a", .data = &axicdma_config },
+       { .compatible = "xlnx,axi-vdma-1.00.a", .data = &axivdma_config },
+       {}
+};
+MODULE_DEVICE_TABLE(of, xilinx_dma_of_ids);
+
+/**
+ * xilinx_dma_probe - Driver probe function
+ * @pdev: Pointer to the platform_device structure
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_dma_probe(struct platform_device *pdev)
+{
+       int (*clk_init)(struct platform_device *, struct clk **, struct clk **,
+                       struct clk **, struct clk **, struct clk **)
+                                       = axivdma_clk_init;
+       struct device_node *node = pdev->dev.of_node;
+       struct xilinx_dma_device *xdev;
+       struct device_node *child, *np = pdev->dev.of_node;
+       struct resource *io;
+       u32 num_frames, addr_width;
+       int i, err;
+
+       /* Allocate and initialize the DMA engine structure */
+       xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL);
+       if (!xdev)
+               return -ENOMEM;
+
+       xdev->dev = &pdev->dev;
+       if (np) {
+               const struct of_device_id *match;
+
+               match = of_match_node(xilinx_dma_of_ids, np);
+               if (match && match->data) {
+                       xdev->dma_config = match->data;
+                       clk_init = xdev->dma_config->clk_init;
+               }
+       }
+
+       err = clk_init(pdev, &xdev->axi_clk, &xdev->tx_clk, &xdev->txs_clk,
+                      &xdev->rx_clk, &xdev->rxs_clk);
+       if (err)
+               return err;
+
+       /* Request and map I/O memory */
+       io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       xdev->regs = devm_ioremap_resource(&pdev->dev, io);
+       if (IS_ERR(xdev->regs))
+               return PTR_ERR(xdev->regs);
+
+       /* Retrieve the DMA engine properties from the device tree */
+       xdev->has_sg = of_property_read_bool(node, "xlnx,include-sg");
+       if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA)
+               xdev->mcdma = of_property_read_bool(node, "xlnx,mcdma");
+
+       if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
+               err = of_property_read_u32(node, "xlnx,num-fstores",
+                                          &num_frames);
+               if (err < 0) {
+                       dev_err(xdev->dev,
+                               "missing xlnx,num-fstores property\n");
+                       return err;
+               }
+
+               err = of_property_read_u32(node, "xlnx,flush-fsync",
+                                          &xdev->flush_on_fsync);
+               if (err < 0)
+                       dev_warn(xdev->dev,
+                                "missing xlnx,flush-fsync property\n");
+       }
+
+       err = of_property_read_u32(node, "xlnx,addrwidth", &addr_width);
+       if (err < 0)
+               dev_warn(xdev->dev, "missing xlnx,addrwidth property\n");
+
+       if (addr_width > 32)
+               xdev->ext_addr = true;
+       else
+               xdev->ext_addr = false;
+
+       /* Set the dma mask bits */
+       dma_set_mask(xdev->dev, DMA_BIT_MASK(addr_width));
+
+       /* Initialize the DMA engine */
+       xdev->common.dev = &pdev->dev;
+
+       INIT_LIST_HEAD(&xdev->common.channels);
+       if (!(xdev->dma_config->dmatype == XDMA_TYPE_CDMA)) {
+               dma_cap_set(DMA_SLAVE, xdev->common.cap_mask);
+               dma_cap_set(DMA_PRIVATE, xdev->common.cap_mask);
+       }
+
+       xdev->common.device_alloc_chan_resources =
+                               xilinx_dma_alloc_chan_resources;
+       xdev->common.device_free_chan_resources =
+                               xilinx_dma_free_chan_resources;
+       xdev->common.device_terminate_all = xilinx_dma_terminate_all;
+       xdev->common.device_tx_status = xilinx_dma_tx_status;
+       xdev->common.device_issue_pending = xilinx_dma_issue_pending;
+       if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
+               dma_cap_set(DMA_CYCLIC, xdev->common.cap_mask);
+               xdev->common.device_prep_slave_sg = xilinx_dma_prep_slave_sg;
+               xdev->common.device_prep_dma_cyclic =
+                                         xilinx_dma_prep_dma_cyclic;
+               xdev->common.device_prep_interleaved_dma =
+                                       xilinx_dma_prep_interleaved;
+               /* Residue calculation is supported by only AXI DMA */
+               xdev->common.residue_granularity =
+                                         DMA_RESIDUE_GRANULARITY_SEGMENT;
+       } else if (xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
+               dma_cap_set(DMA_MEMCPY, xdev->common.cap_mask);
+               xdev->common.device_prep_dma_memcpy = xilinx_cdma_prep_memcpy;
+       } else {
+               xdev->common.device_prep_interleaved_dma =
+                               xilinx_vdma_dma_prep_interleaved;
+       }
+
+       platform_set_drvdata(pdev, xdev);
+
+       /* Initialize the channels */
+       for_each_child_of_node(node, child) {
+               err = xilinx_dma_child_probe(xdev, child);
+               if (err < 0)
+                       goto disable_clks;
+       }
+
+       if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
+               for (i = 0; i < xdev->nr_channels; i++)
+                       if (xdev->chan[i])
+                               xdev->chan[i]->num_frms = num_frames;
+       }
+
+       /* Register the DMA engine with the core */
+       dma_async_device_register(&xdev->common);
+
+       err = of_dma_controller_register(node, of_dma_xilinx_xlate,
+                                        xdev);
+       if (err < 0) {
+               dev_err(&pdev->dev, "Unable to register DMA to DT\n");
+               dma_async_device_unregister(&xdev->common);
+               goto error;
+       }
+
+       dev_info(&pdev->dev, "Xilinx AXI VDMA Engine Driver Probed!!\n");
+
+       return 0;
+
+disable_clks:
+       xdma_disable_allclks(xdev);
+error:
+       for (i = 0; i < xdev->nr_channels; i++)
+               if (xdev->chan[i])
+                       xilinx_dma_chan_remove(xdev->chan[i]);
+
+       return err;
+}
+
+/**
+ * xilinx_dma_remove - Driver remove function
+ * @pdev: Pointer to the platform_device structure
+ *
+ * Return: Always '0'
+ */
+static int xilinx_dma_remove(struct platform_device *pdev)
+{
+       struct xilinx_dma_device *xdev = platform_get_drvdata(pdev);
+       int i;
+
+       of_dma_controller_free(pdev->dev.of_node);
+
+       dma_async_device_unregister(&xdev->common);
+
+       for (i = 0; i < xdev->nr_channels; i++)
+               if (xdev->chan[i])
+                       xilinx_dma_chan_remove(xdev->chan[i]);
+
+       xdma_disable_allclks(xdev);
+
+       return 0;
+}
+
+static struct platform_driver xilinx_vdma_driver = {
+       .driver = {
+               .name = "xilinx-vdma",
+               .of_match_table = xilinx_dma_of_ids,
+       },
+       .probe = xilinx_dma_probe,
+       .remove = xilinx_dma_remove,
+};
+
+module_platform_driver(xilinx_vdma_driver);
+
+MODULE_AUTHOR("Xilinx, Inc.");
+MODULE_DESCRIPTION("Xilinx VDMA driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/xilinx/xilinx_vdma.c b/drivers/dma/xilinx/xilinx_vdma.c
deleted file mode 100644 (file)
index df91185..0000000
+++ /dev/null
@@ -1,2310 +0,0 @@
-/*
- * DMA driver for Xilinx Video DMA Engine
- *
- * Copyright (C) 2010-2014 Xilinx, Inc. All rights reserved.
- *
- * Based on the Freescale DMA driver.
- *
- * Description:
- * The AXI Video Direct Memory Access (AXI VDMA) core is a soft Xilinx IP
- * core that provides high-bandwidth direct memory access between memory
- * and AXI4-Stream type video target peripherals. The core provides efficient
- * two dimensional DMA operations with independent asynchronous read (S2MM)
- * and write (MM2S) channel operation. It can be configured to have either
- * one channel or two channels. If configured as two channels, one is to
- * transmit to the video device (MM2S) and another is to receive from the
- * video device (S2MM). Initialization, status, interrupt and management
- * registers are accessed through an AXI4-Lite slave interface.
- *
- * The AXI Direct Memory Access (AXI DMA) core is a soft Xilinx IP core that
- * provides high-bandwidth one dimensional direct memory access between memory
- * and AXI4-Stream target peripherals. It supports one receive and one
- * transmit channel, both of them optional at synthesis time.
- *
- * The AXI CDMA, is a soft IP, which provides high-bandwidth Direct Memory
- * Access (DMA) between a memory-mapped source address and a memory-mapped
- * destination address.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/bitops.h>
-#include <linux/dmapool.h>
-#include <linux/dma/xilinx_dma.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_dma.h>
-#include <linux/of_platform.h>
-#include <linux/of_irq.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-
-#include "../dmaengine.h"
-
-/* Register/Descriptor Offsets */
-#define XILINX_DMA_MM2S_CTRL_OFFSET            0x0000
-#define XILINX_DMA_S2MM_CTRL_OFFSET            0x0030
-#define XILINX_VDMA_MM2S_DESC_OFFSET           0x0050
-#define XILINX_VDMA_S2MM_DESC_OFFSET           0x00a0
-
-/* Control Registers */
-#define XILINX_DMA_REG_DMACR                   0x0000
-#define XILINX_DMA_DMACR_DELAY_MAX             0xff
-#define XILINX_DMA_DMACR_DELAY_SHIFT           24
-#define XILINX_DMA_DMACR_FRAME_COUNT_MAX       0xff
-#define XILINX_DMA_DMACR_FRAME_COUNT_SHIFT     16
-#define XILINX_DMA_DMACR_ERR_IRQ               BIT(14)
-#define XILINX_DMA_DMACR_DLY_CNT_IRQ           BIT(13)
-#define XILINX_DMA_DMACR_FRM_CNT_IRQ           BIT(12)
-#define XILINX_DMA_DMACR_MASTER_SHIFT          8
-#define XILINX_DMA_DMACR_FSYNCSRC_SHIFT        5
-#define XILINX_DMA_DMACR_FRAMECNT_EN           BIT(4)
-#define XILINX_DMA_DMACR_GENLOCK_EN            BIT(3)
-#define XILINX_DMA_DMACR_RESET                 BIT(2)
-#define XILINX_DMA_DMACR_CIRC_EN               BIT(1)
-#define XILINX_DMA_DMACR_RUNSTOP               BIT(0)
-#define XILINX_DMA_DMACR_FSYNCSRC_MASK         GENMASK(6, 5)
-
-#define XILINX_DMA_REG_DMASR                   0x0004
-#define XILINX_DMA_DMASR_EOL_LATE_ERR          BIT(15)
-#define XILINX_DMA_DMASR_ERR_IRQ               BIT(14)
-#define XILINX_DMA_DMASR_DLY_CNT_IRQ           BIT(13)
-#define XILINX_DMA_DMASR_FRM_CNT_IRQ           BIT(12)
-#define XILINX_DMA_DMASR_SOF_LATE_ERR          BIT(11)
-#define XILINX_DMA_DMASR_SG_DEC_ERR            BIT(10)
-#define XILINX_DMA_DMASR_SG_SLV_ERR            BIT(9)
-#define XILINX_DMA_DMASR_EOF_EARLY_ERR         BIT(8)
-#define XILINX_DMA_DMASR_SOF_EARLY_ERR         BIT(7)
-#define XILINX_DMA_DMASR_DMA_DEC_ERR           BIT(6)
-#define XILINX_DMA_DMASR_DMA_SLAVE_ERR         BIT(5)
-#define XILINX_DMA_DMASR_DMA_INT_ERR           BIT(4)
-#define XILINX_DMA_DMASR_IDLE                  BIT(1)
-#define XILINX_DMA_DMASR_HALTED                BIT(0)
-#define XILINX_DMA_DMASR_DELAY_MASK            GENMASK(31, 24)
-#define XILINX_DMA_DMASR_FRAME_COUNT_MASK      GENMASK(23, 16)
-
-#define XILINX_DMA_REG_CURDESC                 0x0008
-#define XILINX_DMA_REG_TAILDESC                0x0010
-#define XILINX_DMA_REG_REG_INDEX               0x0014
-#define XILINX_DMA_REG_FRMSTORE                0x0018
-#define XILINX_DMA_REG_THRESHOLD               0x001c
-#define XILINX_DMA_REG_FRMPTR_STS              0x0024
-#define XILINX_DMA_REG_PARK_PTR                0x0028
-#define XILINX_DMA_PARK_PTR_WR_REF_SHIFT       8
-#define XILINX_DMA_PARK_PTR_RD_REF_SHIFT       0
-#define XILINX_DMA_REG_VDMA_VERSION            0x002c
-
-/* Register Direct Mode Registers */
-#define XILINX_DMA_REG_VSIZE                   0x0000
-#define XILINX_DMA_REG_HSIZE                   0x0004
-
-#define XILINX_DMA_REG_FRMDLY_STRIDE           0x0008
-#define XILINX_DMA_FRMDLY_STRIDE_FRMDLY_SHIFT  24
-#define XILINX_DMA_FRMDLY_STRIDE_STRIDE_SHIFT  0
-
-#define XILINX_VDMA_REG_START_ADDRESS(n)       (0x000c + 4 * (n))
-#define XILINX_VDMA_REG_START_ADDRESS_64(n)    (0x000c + 8 * (n))
-
-/* HW specific definitions */
-#define XILINX_DMA_MAX_CHANS_PER_DEVICE        0x2
-
-#define XILINX_DMA_DMAXR_ALL_IRQ_MASK  \
-               (XILINX_DMA_DMASR_FRM_CNT_IRQ | \
-                XILINX_DMA_DMASR_DLY_CNT_IRQ | \
-                XILINX_DMA_DMASR_ERR_IRQ)
-
-#define XILINX_DMA_DMASR_ALL_ERR_MASK  \
-               (XILINX_DMA_DMASR_EOL_LATE_ERR | \
-                XILINX_DMA_DMASR_SOF_LATE_ERR | \
-                XILINX_DMA_DMASR_SG_DEC_ERR | \
-                XILINX_DMA_DMASR_SG_SLV_ERR | \
-                XILINX_DMA_DMASR_EOF_EARLY_ERR | \
-                XILINX_DMA_DMASR_SOF_EARLY_ERR | \
-                XILINX_DMA_DMASR_DMA_DEC_ERR | \
-                XILINX_DMA_DMASR_DMA_SLAVE_ERR | \
-                XILINX_DMA_DMASR_DMA_INT_ERR)
-
-/*
- * Recoverable errors are DMA Internal error, SOF Early, EOF Early
- * and SOF Late. They are only recoverable when C_FLUSH_ON_FSYNC
- * is enabled in the h/w system.
- */
-#define XILINX_DMA_DMASR_ERR_RECOVER_MASK      \
-               (XILINX_DMA_DMASR_SOF_LATE_ERR | \
-                XILINX_DMA_DMASR_EOF_EARLY_ERR | \
-                XILINX_DMA_DMASR_SOF_EARLY_ERR | \
-                XILINX_DMA_DMASR_DMA_INT_ERR)
-
-/* Axi VDMA Flush on Fsync bits */
-#define XILINX_DMA_FLUSH_S2MM          3
-#define XILINX_DMA_FLUSH_MM2S          2
-#define XILINX_DMA_FLUSH_BOTH          1
-
-/* Delay loop counter to prevent hardware failure */
-#define XILINX_DMA_LOOP_COUNT          1000000
-
-/* AXI DMA Specific Registers/Offsets */
-#define XILINX_DMA_REG_SRCDSTADDR      0x18
-#define XILINX_DMA_REG_BTT             0x28
-
-/* AXI DMA Specific Masks/Bit fields */
-#define XILINX_DMA_MAX_TRANS_LEN       GENMASK(22, 0)
-#define XILINX_DMA_CR_COALESCE_MAX     GENMASK(23, 16)
-#define XILINX_DMA_CR_COALESCE_SHIFT   16
-#define XILINX_DMA_BD_SOP              BIT(27)
-#define XILINX_DMA_BD_EOP              BIT(26)
-#define XILINX_DMA_COALESCE_MAX                255
-#define XILINX_DMA_NUM_APP_WORDS       5
-
-/* AXI CDMA Specific Registers/Offsets */
-#define XILINX_CDMA_REG_SRCADDR                0x18
-#define XILINX_CDMA_REG_DSTADDR                0x20
-
-/* AXI CDMA Specific Masks */
-#define XILINX_CDMA_CR_SGMODE          BIT(3)
-
-/**
- * struct xilinx_vdma_desc_hw - Hardware Descriptor
- * @next_desc: Next Descriptor Pointer @0x00
- * @pad1: Reserved @0x04
- * @buf_addr: Buffer address @0x08
- * @buf_addr_msb: MSB of Buffer address @0x0C
- * @vsize: Vertical Size @0x10
- * @hsize: Horizontal Size @0x14
- * @stride: Number of bytes between the first
- *         pixels of each horizontal line @0x18
- */
-struct xilinx_vdma_desc_hw {
-       u32 next_desc;
-       u32 pad1;
-       u32 buf_addr;
-       u32 buf_addr_msb;
-       u32 vsize;
-       u32 hsize;
-       u32 stride;
-} __aligned(64);
-
-/**
- * struct xilinx_axidma_desc_hw - Hardware Descriptor for AXI DMA
- * @next_desc: Next Descriptor Pointer @0x00
- * @pad1: Reserved @0x04
- * @buf_addr: Buffer address @0x08
- * @pad2: Reserved @0x0C
- * @pad3: Reserved @0x10
- * @pad4: Reserved @0x14
- * @control: Control field @0x18
- * @status: Status field @0x1C
- * @app: APP Fields @0x20 - 0x30
- */
-struct xilinx_axidma_desc_hw {
-       u32 next_desc;
-       u32 pad1;
-       u32 buf_addr;
-       u32 pad2;
-       u32 pad3;
-       u32 pad4;
-       u32 control;
-       u32 status;
-       u32 app[XILINX_DMA_NUM_APP_WORDS];
-} __aligned(64);
-
-/**
- * struct xilinx_cdma_desc_hw - Hardware Descriptor
- * @next_desc: Next Descriptor Pointer @0x00
- * @pad1: Reserved @0x04
- * @src_addr: Source address @0x08
- * @pad2: Reserved @0x0C
- * @dest_addr: Destination address @0x10
- * @pad3: Reserved @0x14
- * @control: Control field @0x18
- * @status: Status field @0x1C
- */
-struct xilinx_cdma_desc_hw {
-       u32 next_desc;
-       u32 pad1;
-       u32 src_addr;
-       u32 pad2;
-       u32 dest_addr;
-       u32 pad3;
-       u32 control;
-       u32 status;
-} __aligned(64);
-
-/**
- * struct xilinx_vdma_tx_segment - Descriptor segment
- * @hw: Hardware descriptor
- * @node: Node in the descriptor segments list
- * @phys: Physical address of segment
- */
-struct xilinx_vdma_tx_segment {
-       struct xilinx_vdma_desc_hw hw;
-       struct list_head node;
-       dma_addr_t phys;
-} __aligned(64);
-
-/**
- * struct xilinx_axidma_tx_segment - Descriptor segment
- * @hw: Hardware descriptor
- * @node: Node in the descriptor segments list
- * @phys: Physical address of segment
- */
-struct xilinx_axidma_tx_segment {
-       struct xilinx_axidma_desc_hw hw;
-       struct list_head node;
-       dma_addr_t phys;
-} __aligned(64);
-
-/**
- * struct xilinx_cdma_tx_segment - Descriptor segment
- * @hw: Hardware descriptor
- * @node: Node in the descriptor segments list
- * @phys: Physical address of segment
- */
-struct xilinx_cdma_tx_segment {
-       struct xilinx_cdma_desc_hw hw;
-       struct list_head node;
-       dma_addr_t phys;
-} __aligned(64);
-
-/**
- * struct xilinx_dma_tx_descriptor - Per Transaction structure
- * @async_tx: Async transaction descriptor
- * @segments: TX segments list
- * @node: Node in the channel descriptors list
- */
-struct xilinx_dma_tx_descriptor {
-       struct dma_async_tx_descriptor async_tx;
-       struct list_head segments;
-       struct list_head node;
-};
-
-/**
- * struct xilinx_dma_chan - Driver specific DMA channel structure
- * @xdev: Driver specific device structure
- * @ctrl_offset: Control registers offset
- * @desc_offset: TX descriptor registers offset
- * @lock: Descriptor operation lock
- * @pending_list: Descriptors waiting
- * @active_list: Descriptors ready to submit
- * @done_list: Complete descriptors
- * @common: DMA common channel
- * @desc_pool: Descriptors pool
- * @dev: The dma device
- * @irq: Channel IRQ
- * @id: Channel ID
- * @direction: Transfer direction
- * @num_frms: Number of frames
- * @has_sg: Support scatter transfers
- * @genlock: Support genlock mode
- * @err: Channel has errors
- * @tasklet: Cleanup work after irq
- * @config: Device configuration info
- * @flush_on_fsync: Flush on Frame sync
- * @desc_pendingcount: Descriptor pending count
- * @ext_addr: Indicates 64 bit addressing is supported by dma channel
- * @desc_submitcount: Descriptor h/w submitted count
- * @residue: Residue for AXI DMA
- * @seg_v: Statically allocated segments base
- * @start_transfer: Differentiate b/w DMA IP's transfer
- */
-struct xilinx_dma_chan {
-       struct xilinx_dma_device *xdev;
-       u32 ctrl_offset;
-       u32 desc_offset;
-       spinlock_t lock;
-       struct list_head pending_list;
-       struct list_head active_list;
-       struct list_head done_list;
-       struct dma_chan common;
-       struct dma_pool *desc_pool;
-       struct device *dev;
-       int irq;
-       int id;
-       enum dma_transfer_direction direction;
-       int num_frms;
-       bool has_sg;
-       bool genlock;
-       bool err;
-       struct tasklet_struct tasklet;
-       struct xilinx_vdma_config config;
-       bool flush_on_fsync;
-       u32 desc_pendingcount;
-       bool ext_addr;
-       u32 desc_submitcount;
-       u32 residue;
-       struct xilinx_axidma_tx_segment *seg_v;
-       void (*start_transfer)(struct xilinx_dma_chan *chan);
-};
-
-struct xilinx_dma_config {
-       enum xdma_ip_type dmatype;
-       int (*clk_init)(struct platform_device *pdev, struct clk **axi_clk,
-                       struct clk **tx_clk, struct clk **txs_clk,
-                       struct clk **rx_clk, struct clk **rxs_clk);
-};
-
-/**
- * struct xilinx_dma_device - DMA device structure
- * @regs: I/O mapped base address
- * @dev: Device Structure
- * @common: DMA device structure
- * @chan: Driver specific DMA channel
- * @has_sg: Specifies whether Scatter-Gather is present or not
- * @flush_on_fsync: Flush on frame sync
- * @ext_addr: Indicates 64 bit addressing is supported by dma device
- * @pdev: Platform device structure pointer
- * @dma_config: DMA config structure
- * @axi_clk: DMA Axi4-lite interace clock
- * @tx_clk: DMA mm2s clock
- * @txs_clk: DMA mm2s stream clock
- * @rx_clk: DMA s2mm clock
- * @rxs_clk: DMA s2mm stream clock
- */
-struct xilinx_dma_device {
-       void __iomem *regs;
-       struct device *dev;
-       struct dma_device common;
-       struct xilinx_dma_chan *chan[XILINX_DMA_MAX_CHANS_PER_DEVICE];
-       bool has_sg;
-       u32 flush_on_fsync;
-       bool ext_addr;
-       struct platform_device  *pdev;
-       const struct xilinx_dma_config *dma_config;
-       struct clk *axi_clk;
-       struct clk *tx_clk;
-       struct clk *txs_clk;
-       struct clk *rx_clk;
-       struct clk *rxs_clk;
-};
-
-/* Macros */
-#define to_xilinx_chan(chan) \
-       container_of(chan, struct xilinx_dma_chan, common)
-#define to_dma_tx_descriptor(tx) \
-       container_of(tx, struct xilinx_dma_tx_descriptor, async_tx)
-#define xilinx_dma_poll_timeout(chan, reg, val, cond, delay_us, timeout_us) \
-       readl_poll_timeout(chan->xdev->regs + chan->ctrl_offset + reg, val, \
-                          cond, delay_us, timeout_us)
-
-/* IO accessors */
-static inline u32 dma_read(struct xilinx_dma_chan *chan, u32 reg)
-{
-       return ioread32(chan->xdev->regs + reg);
-}
-
-static inline void dma_write(struct xilinx_dma_chan *chan, u32 reg, u32 value)
-{
-       iowrite32(value, chan->xdev->regs + reg);
-}
-
-static inline void vdma_desc_write(struct xilinx_dma_chan *chan, u32 reg,
-                                  u32 value)
-{
-       dma_write(chan, chan->desc_offset + reg, value);
-}
-
-static inline u32 dma_ctrl_read(struct xilinx_dma_chan *chan, u32 reg)
-{
-       return dma_read(chan, chan->ctrl_offset + reg);
-}
-
-static inline void dma_ctrl_write(struct xilinx_dma_chan *chan, u32 reg,
-                                  u32 value)
-{
-       dma_write(chan, chan->ctrl_offset + reg, value);
-}
-
-static inline void dma_ctrl_clr(struct xilinx_dma_chan *chan, u32 reg,
-                                u32 clr)
-{
-       dma_ctrl_write(chan, reg, dma_ctrl_read(chan, reg) & ~clr);
-}
-
-static inline void dma_ctrl_set(struct xilinx_dma_chan *chan, u32 reg,
-                                u32 set)
-{
-       dma_ctrl_write(chan, reg, dma_ctrl_read(chan, reg) | set);
-}
-
-/**
- * vdma_desc_write_64 - 64-bit descriptor write
- * @chan: Driver specific VDMA channel
- * @reg: Register to write
- * @value_lsb: lower address of the descriptor.
- * @value_msb: upper address of the descriptor.
- *
- * Since vdma driver is trying to write to a register offset which is not a
- * multiple of 64 bits(ex : 0x5c), we are writing as two separate 32 bits
- * instead of a single 64 bit register write.
- */
-static inline void vdma_desc_write_64(struct xilinx_dma_chan *chan, u32 reg,
-                                     u32 value_lsb, u32 value_msb)
-{
-       /* Write the lsb 32 bits*/
-       writel(value_lsb, chan->xdev->regs + chan->desc_offset + reg);
-
-       /* Write the msb 32 bits */
-       writel(value_msb, chan->xdev->regs + chan->desc_offset + reg + 4);
-}
-
-/* -----------------------------------------------------------------------------
- * Descriptors and segments alloc and free
- */
-
-/**
- * xilinx_vdma_alloc_tx_segment - Allocate transaction segment
- * @chan: Driver specific DMA channel
- *
- * Return: The allocated segment on success and NULL on failure.
- */
-static struct xilinx_vdma_tx_segment *
-xilinx_vdma_alloc_tx_segment(struct xilinx_dma_chan *chan)
-{
-       struct xilinx_vdma_tx_segment *segment;
-       dma_addr_t phys;
-
-       segment = dma_pool_zalloc(chan->desc_pool, GFP_ATOMIC, &phys);
-       if (!segment)
-               return NULL;
-
-       segment->phys = phys;
-
-       return segment;
-}
-
-/**
- * xilinx_cdma_alloc_tx_segment - Allocate transaction segment
- * @chan: Driver specific DMA channel
- *
- * Return: The allocated segment on success and NULL on failure.
- */
-static struct xilinx_cdma_tx_segment *
-xilinx_cdma_alloc_tx_segment(struct xilinx_dma_chan *chan)
-{
-       struct xilinx_cdma_tx_segment *segment;
-       dma_addr_t phys;
-
-       segment = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &phys);
-       if (!segment)
-               return NULL;
-
-       memset(segment, 0, sizeof(*segment));
-       segment->phys = phys;
-
-       return segment;
-}
-
-/**
- * xilinx_axidma_alloc_tx_segment - Allocate transaction segment
- * @chan: Driver specific DMA channel
- *
- * Return: The allocated segment on success and NULL on failure.
- */
-static struct xilinx_axidma_tx_segment *
-xilinx_axidma_alloc_tx_segment(struct xilinx_dma_chan *chan)
-{
-       struct xilinx_axidma_tx_segment *segment;
-       dma_addr_t phys;
-
-       segment = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &phys);
-       if (!segment)
-               return NULL;
-
-       memset(segment, 0, sizeof(*segment));
-       segment->phys = phys;
-
-       return segment;
-}
-
-/**
- * xilinx_dma_free_tx_segment - Free transaction segment
- * @chan: Driver specific DMA channel
- * @segment: DMA transaction segment
- */
-static void xilinx_dma_free_tx_segment(struct xilinx_dma_chan *chan,
-                               struct xilinx_axidma_tx_segment *segment)
-{
-       dma_pool_free(chan->desc_pool, segment, segment->phys);
-}
-
-/**
- * xilinx_cdma_free_tx_segment - Free transaction segment
- * @chan: Driver specific DMA channel
- * @segment: DMA transaction segment
- */
-static void xilinx_cdma_free_tx_segment(struct xilinx_dma_chan *chan,
-                               struct xilinx_cdma_tx_segment *segment)
-{
-       dma_pool_free(chan->desc_pool, segment, segment->phys);
-}
-
-/**
- * xilinx_vdma_free_tx_segment - Free transaction segment
- * @chan: Driver specific DMA channel
- * @segment: DMA transaction segment
- */
-static void xilinx_vdma_free_tx_segment(struct xilinx_dma_chan *chan,
-                                       struct xilinx_vdma_tx_segment *segment)
-{
-       dma_pool_free(chan->desc_pool, segment, segment->phys);
-}
-
-/**
- * xilinx_dma_tx_descriptor - Allocate transaction descriptor
- * @chan: Driver specific DMA channel
- *
- * Return: The allocated descriptor on success and NULL on failure.
- */
-static struct xilinx_dma_tx_descriptor *
-xilinx_dma_alloc_tx_descriptor(struct xilinx_dma_chan *chan)
-{
-       struct xilinx_dma_tx_descriptor *desc;
-
-       desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-       if (!desc)
-               return NULL;
-
-       INIT_LIST_HEAD(&desc->segments);
-
-       return desc;
-}
-
-/**
- * xilinx_dma_free_tx_descriptor - Free transaction descriptor
- * @chan: Driver specific DMA channel
- * @desc: DMA transaction descriptor
- */
-static void
-xilinx_dma_free_tx_descriptor(struct xilinx_dma_chan *chan,
-                              struct xilinx_dma_tx_descriptor *desc)
-{
-       struct xilinx_vdma_tx_segment *segment, *next;
-       struct xilinx_cdma_tx_segment *cdma_segment, *cdma_next;
-       struct xilinx_axidma_tx_segment *axidma_segment, *axidma_next;
-
-       if (!desc)
-               return;
-
-       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
-               list_for_each_entry_safe(segment, next, &desc->segments, node) {
-                       list_del(&segment->node);
-                       xilinx_vdma_free_tx_segment(chan, segment);
-               }
-       } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
-               list_for_each_entry_safe(cdma_segment, cdma_next,
-                                        &desc->segments, node) {
-                       list_del(&cdma_segment->node);
-                       xilinx_cdma_free_tx_segment(chan, cdma_segment);
-               }
-       } else {
-               list_for_each_entry_safe(axidma_segment, axidma_next,
-                                        &desc->segments, node) {
-                       list_del(&axidma_segment->node);
-                       xilinx_dma_free_tx_segment(chan, axidma_segment);
-               }
-       }
-
-       kfree(desc);
-}
-
-/* Required functions */
-
-/**
- * xilinx_dma_free_desc_list - Free descriptors list
- * @chan: Driver specific DMA channel
- * @list: List to parse and delete the descriptor
- */
-static void xilinx_dma_free_desc_list(struct xilinx_dma_chan *chan,
-                                       struct list_head *list)
-{
-       struct xilinx_dma_tx_descriptor *desc, *next;
-
-       list_for_each_entry_safe(desc, next, list, node) {
-               list_del(&desc->node);
-               xilinx_dma_free_tx_descriptor(chan, desc);
-       }
-}
-
-/**
- * xilinx_dma_free_descriptors - Free channel descriptors
- * @chan: Driver specific DMA channel
- */
-static void xilinx_dma_free_descriptors(struct xilinx_dma_chan *chan)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&chan->lock, flags);
-
-       xilinx_dma_free_desc_list(chan, &chan->pending_list);
-       xilinx_dma_free_desc_list(chan, &chan->done_list);
-       xilinx_dma_free_desc_list(chan, &chan->active_list);
-
-       spin_unlock_irqrestore(&chan->lock, flags);
-}
-
-/**
- * xilinx_dma_free_chan_resources - Free channel resources
- * @dchan: DMA channel
- */
-static void xilinx_dma_free_chan_resources(struct dma_chan *dchan)
-{
-       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
-
-       dev_dbg(chan->dev, "Free all channel resources.\n");
-
-       xilinx_dma_free_descriptors(chan);
-       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA)
-               xilinx_dma_free_tx_segment(chan, chan->seg_v);
-       dma_pool_destroy(chan->desc_pool);
-       chan->desc_pool = NULL;
-}
-
-/**
- * xilinx_dma_chan_desc_cleanup - Clean channel descriptors
- * @chan: Driver specific DMA channel
- */
-static void xilinx_dma_chan_desc_cleanup(struct xilinx_dma_chan *chan)
-{
-       struct xilinx_dma_tx_descriptor *desc, *next;
-       unsigned long flags;
-
-       spin_lock_irqsave(&chan->lock, flags);
-
-       list_for_each_entry_safe(desc, next, &chan->done_list, node) {
-               dma_async_tx_callback callback;
-               void *callback_param;
-
-               /* Remove from the list of running transactions */
-               list_del(&desc->node);
-
-               /* Run the link descriptor callback function */
-               callback = desc->async_tx.callback;
-               callback_param = desc->async_tx.callback_param;
-               if (callback) {
-                       spin_unlock_irqrestore(&chan->lock, flags);
-                       callback(callback_param);
-                       spin_lock_irqsave(&chan->lock, flags);
-               }
-
-               /* Run any dependencies, then free the descriptor */
-               dma_run_dependencies(&desc->async_tx);
-               xilinx_dma_free_tx_descriptor(chan, desc);
-       }
-
-       spin_unlock_irqrestore(&chan->lock, flags);
-}
-
-/**
- * xilinx_dma_do_tasklet - Schedule completion tasklet
- * @data: Pointer to the Xilinx DMA channel structure
- */
-static void xilinx_dma_do_tasklet(unsigned long data)
-{
-       struct xilinx_dma_chan *chan = (struct xilinx_dma_chan *)data;
-
-       xilinx_dma_chan_desc_cleanup(chan);
-}
-
-/**
- * xilinx_dma_alloc_chan_resources - Allocate channel resources
- * @dchan: DMA channel
- *
- * Return: '0' on success and failure value on error
- */
-static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan)
-{
-       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
-
-       /* Has this channel already been allocated? */
-       if (chan->desc_pool)
-               return 0;
-
-       /*
-        * We need the descriptor to be aligned to 64bytes
-        * for meeting Xilinx VDMA specification requirement.
-        */
-       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
-               chan->desc_pool = dma_pool_create("xilinx_dma_desc_pool",
-                                  chan->dev,
-                                  sizeof(struct xilinx_axidma_tx_segment),
-                                  __alignof__(struct xilinx_axidma_tx_segment),
-                                  0);
-       } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
-               chan->desc_pool = dma_pool_create("xilinx_cdma_desc_pool",
-                                  chan->dev,
-                                  sizeof(struct xilinx_cdma_tx_segment),
-                                  __alignof__(struct xilinx_cdma_tx_segment),
-                                  0);
-       } else {
-               chan->desc_pool = dma_pool_create("xilinx_vdma_desc_pool",
-                                    chan->dev,
-                                    sizeof(struct xilinx_vdma_tx_segment),
-                                    __alignof__(struct xilinx_vdma_tx_segment),
-                                    0);
-       }
-
-       if (!chan->desc_pool) {
-               dev_err(chan->dev,
-                       "unable to allocate channel %d descriptor pool\n",
-                       chan->id);
-               return -ENOMEM;
-       }
-
-       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA)
-               /*
-                * For AXI DMA case after submitting a pending_list, keep
-                * an extra segment allocated so that the "next descriptor"
-                * pointer on the tail descriptor always points to a
-                * valid descriptor, even when paused after reaching taildesc.
-                * This way, it is possible to issue additional
-                * transfers without halting and restarting the channel.
-                */
-               chan->seg_v = xilinx_axidma_alloc_tx_segment(chan);
-
-       dma_cookie_init(dchan);
-
-       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
-               /* For AXI DMA resetting once channel will reset the
-                * other channel as well so enable the interrupts here.
-                */
-               dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
-                             XILINX_DMA_DMAXR_ALL_IRQ_MASK);
-       }
-
-       if ((chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) && chan->has_sg)
-               dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
-                            XILINX_CDMA_CR_SGMODE);
-
-       return 0;
-}
-
-/**
- * xilinx_dma_tx_status - Get DMA transaction status
- * @dchan: DMA channel
- * @cookie: Transaction identifier
- * @txstate: Transaction state
- *
- * Return: DMA transaction status
- */
-static enum dma_status xilinx_dma_tx_status(struct dma_chan *dchan,
-                                       dma_cookie_t cookie,
-                                       struct dma_tx_state *txstate)
-{
-       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
-       struct xilinx_dma_tx_descriptor *desc;
-       struct xilinx_axidma_tx_segment *segment;
-       struct xilinx_axidma_desc_hw *hw;
-       enum dma_status ret;
-       unsigned long flags;
-       u32 residue = 0;
-
-       ret = dma_cookie_status(dchan, cookie, txstate);
-       if (ret == DMA_COMPLETE || !txstate)
-               return ret;
-
-       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
-               spin_lock_irqsave(&chan->lock, flags);
-
-               desc = list_last_entry(&chan->active_list,
-                                      struct xilinx_dma_tx_descriptor, node);
-               if (chan->has_sg) {
-                       list_for_each_entry(segment, &desc->segments, node) {
-                               hw = &segment->hw;
-                               residue += (hw->control - hw->status) &
-                                          XILINX_DMA_MAX_TRANS_LEN;
-                       }
-               }
-               spin_unlock_irqrestore(&chan->lock, flags);
-
-               chan->residue = residue;
-               dma_set_residue(txstate, chan->residue);
-       }
-
-       return ret;
-}
-
-/**
- * xilinx_dma_is_running - Check if DMA channel is running
- * @chan: Driver specific DMA channel
- *
- * Return: '1' if running, '0' if not.
- */
-static bool xilinx_dma_is_running(struct xilinx_dma_chan *chan)
-{
-       return !(dma_ctrl_read(chan, XILINX_DMA_REG_DMASR) &
-                XILINX_DMA_DMASR_HALTED) &&
-               (dma_ctrl_read(chan, XILINX_DMA_REG_DMACR) &
-                XILINX_DMA_DMACR_RUNSTOP);
-}
-
-/**
- * xilinx_dma_is_idle - Check if DMA channel is idle
- * @chan: Driver specific DMA channel
- *
- * Return: '1' if idle, '0' if not.
- */
-static bool xilinx_dma_is_idle(struct xilinx_dma_chan *chan)
-{
-       return dma_ctrl_read(chan, XILINX_DMA_REG_DMASR) &
-               XILINX_DMA_DMASR_IDLE;
-}
-
-/**
- * xilinx_dma_halt - Halt DMA channel
- * @chan: Driver specific DMA channel
- */
-static void xilinx_dma_halt(struct xilinx_dma_chan *chan)
-{
-       int err;
-       u32 val;
-
-       dma_ctrl_clr(chan, XILINX_DMA_REG_DMACR, XILINX_DMA_DMACR_RUNSTOP);
-
-       /* Wait for the hardware to halt */
-       err = xilinx_dma_poll_timeout(chan, XILINX_DMA_REG_DMASR, val,
-                                     (val & XILINX_DMA_DMASR_HALTED), 0,
-                                     XILINX_DMA_LOOP_COUNT);
-
-       if (err) {
-               dev_err(chan->dev, "Cannot stop channel %p: %x\n",
-                       chan, dma_ctrl_read(chan, XILINX_DMA_REG_DMASR));
-               chan->err = true;
-       }
-}
-
-/**
- * xilinx_dma_start - Start DMA channel
- * @chan: Driver specific DMA channel
- */
-static void xilinx_dma_start(struct xilinx_dma_chan *chan)
-{
-       int err;
-       u32 val;
-
-       dma_ctrl_set(chan, XILINX_DMA_REG_DMACR, XILINX_DMA_DMACR_RUNSTOP);
-
-       /* Wait for the hardware to start */
-       err = xilinx_dma_poll_timeout(chan, XILINX_DMA_REG_DMASR, val,
-                                     !(val & XILINX_DMA_DMASR_HALTED), 0,
-                                     XILINX_DMA_LOOP_COUNT);
-
-       if (err) {
-               dev_err(chan->dev, "Cannot start channel %p: %x\n",
-                       chan, dma_ctrl_read(chan, XILINX_DMA_REG_DMASR));
-
-               chan->err = true;
-       }
-}
-
-/**
- * xilinx_vdma_start_transfer - Starts VDMA transfer
- * @chan: Driver specific channel struct pointer
- */
-static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan)
-{
-       struct xilinx_vdma_config *config = &chan->config;
-       struct xilinx_dma_tx_descriptor *desc, *tail_desc;
-       u32 reg;
-       struct xilinx_vdma_tx_segment *tail_segment;
-
-       /* This function was invoked with lock held */
-       if (chan->err)
-               return;
-
-       if (list_empty(&chan->pending_list))
-               return;
-
-       desc = list_first_entry(&chan->pending_list,
-                               struct xilinx_dma_tx_descriptor, node);
-       tail_desc = list_last_entry(&chan->pending_list,
-                                   struct xilinx_dma_tx_descriptor, node);
-
-       tail_segment = list_last_entry(&tail_desc->segments,
-                                      struct xilinx_vdma_tx_segment, node);
-
-       /* If it is SG mode and hardware is busy, cannot submit */
-       if (chan->has_sg && xilinx_dma_is_running(chan) &&
-           !xilinx_dma_is_idle(chan)) {
-               dev_dbg(chan->dev, "DMA controller still busy\n");
-               return;
-       }
-
-       /*
-        * If hardware is idle, then all descriptors on the running lists are
-        * done, start new transfers
-        */
-       if (chan->has_sg)
-               dma_ctrl_write(chan, XILINX_DMA_REG_CURDESC,
-                               desc->async_tx.phys);
-
-       /* Configure the hardware using info in the config structure */
-       reg = dma_ctrl_read(chan, XILINX_DMA_REG_DMACR);
-
-       if (config->frm_cnt_en)
-               reg |= XILINX_DMA_DMACR_FRAMECNT_EN;
-       else
-               reg &= ~XILINX_DMA_DMACR_FRAMECNT_EN;
-
-       /* Configure channel to allow number frame buffers */
-       dma_ctrl_write(chan, XILINX_DMA_REG_FRMSTORE,
-                       chan->desc_pendingcount);
-
-       /*
-        * With SG, start with circular mode, so that BDs can be fetched.
-        * In direct register mode, if not parking, enable circular mode
-        */
-       if (chan->has_sg || !config->park)
-               reg |= XILINX_DMA_DMACR_CIRC_EN;
-
-       if (config->park)
-               reg &= ~XILINX_DMA_DMACR_CIRC_EN;
-
-       dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
-
-       if (config->park && (config->park_frm >= 0) &&
-                       (config->park_frm < chan->num_frms)) {
-               if (chan->direction == DMA_MEM_TO_DEV)
-                       dma_write(chan, XILINX_DMA_REG_PARK_PTR,
-                               config->park_frm <<
-                                       XILINX_DMA_PARK_PTR_RD_REF_SHIFT);
-               else
-                       dma_write(chan, XILINX_DMA_REG_PARK_PTR,
-                               config->park_frm <<
-                                       XILINX_DMA_PARK_PTR_WR_REF_SHIFT);
-       }
-
-       /* Start the hardware */
-       xilinx_dma_start(chan);
-
-       if (chan->err)
-               return;
-
-       /* Start the transfer */
-       if (chan->has_sg) {
-               dma_ctrl_write(chan, XILINX_DMA_REG_TAILDESC,
-                               tail_segment->phys);
-       } else {
-               struct xilinx_vdma_tx_segment *segment, *last = NULL;
-               int i = 0;
-
-               if (chan->desc_submitcount < chan->num_frms)
-                       i = chan->desc_submitcount;
-
-               list_for_each_entry(segment, &desc->segments, node) {
-                       if (chan->ext_addr)
-                               vdma_desc_write_64(chan,
-                                       XILINX_VDMA_REG_START_ADDRESS_64(i++),
-                                       segment->hw.buf_addr,
-                                       segment->hw.buf_addr_msb);
-                       else
-                               vdma_desc_write(chan,
-                                       XILINX_VDMA_REG_START_ADDRESS(i++),
-                                       segment->hw.buf_addr);
-
-                       last = segment;
-               }
-
-               if (!last)
-                       return;
-
-               /* HW expects these parameters to be same for one transaction */
-               vdma_desc_write(chan, XILINX_DMA_REG_HSIZE, last->hw.hsize);
-               vdma_desc_write(chan, XILINX_DMA_REG_FRMDLY_STRIDE,
-                               last->hw.stride);
-               vdma_desc_write(chan, XILINX_DMA_REG_VSIZE, last->hw.vsize);
-       }
-
-       if (!chan->has_sg) {
-               list_del(&desc->node);
-               list_add_tail(&desc->node, &chan->active_list);
-               chan->desc_submitcount++;
-               chan->desc_pendingcount--;
-               if (chan->desc_submitcount == chan->num_frms)
-                       chan->desc_submitcount = 0;
-       } else {
-               list_splice_tail_init(&chan->pending_list, &chan->active_list);
-               chan->desc_pendingcount = 0;
-       }
-}
-
-/**
- * xilinx_cdma_start_transfer - Starts cdma transfer
- * @chan: Driver specific channel struct pointer
- */
-static void xilinx_cdma_start_transfer(struct xilinx_dma_chan *chan)
-{
-       struct xilinx_dma_tx_descriptor *head_desc, *tail_desc;
-       struct xilinx_cdma_tx_segment *tail_segment;
-       u32 ctrl_reg = dma_read(chan, XILINX_DMA_REG_DMACR);
-
-       if (chan->err)
-               return;
-
-       if (list_empty(&chan->pending_list))
-               return;
-
-       head_desc = list_first_entry(&chan->pending_list,
-                                    struct xilinx_dma_tx_descriptor, node);
-       tail_desc = list_last_entry(&chan->pending_list,
-                                   struct xilinx_dma_tx_descriptor, node);
-       tail_segment = list_last_entry(&tail_desc->segments,
-                                      struct xilinx_cdma_tx_segment, node);
-
-       if (chan->desc_pendingcount <= XILINX_DMA_COALESCE_MAX) {
-               ctrl_reg &= ~XILINX_DMA_CR_COALESCE_MAX;
-               ctrl_reg |= chan->desc_pendingcount <<
-                               XILINX_DMA_CR_COALESCE_SHIFT;
-               dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, ctrl_reg);
-       }
-
-       if (chan->has_sg) {
-               dma_ctrl_write(chan, XILINX_DMA_REG_CURDESC,
-                          head_desc->async_tx.phys);
-
-               /* Update tail ptr register which will start the transfer */
-               dma_ctrl_write(chan, XILINX_DMA_REG_TAILDESC,
-                              tail_segment->phys);
-       } else {
-               /* In simple mode */
-               struct xilinx_cdma_tx_segment *segment;
-               struct xilinx_cdma_desc_hw *hw;
-
-               segment = list_first_entry(&head_desc->segments,
-                                          struct xilinx_cdma_tx_segment,
-                                          node);
-
-               hw = &segment->hw;
-
-               dma_ctrl_write(chan, XILINX_CDMA_REG_SRCADDR, hw->src_addr);
-               dma_ctrl_write(chan, XILINX_CDMA_REG_DSTADDR, hw->dest_addr);
-
-               /* Start the transfer */
-               dma_ctrl_write(chan, XILINX_DMA_REG_BTT,
-                               hw->control & XILINX_DMA_MAX_TRANS_LEN);
-       }
-
-       list_splice_tail_init(&chan->pending_list, &chan->active_list);
-       chan->desc_pendingcount = 0;
-}
-
-/**
- * xilinx_dma_start_transfer - Starts DMA transfer
- * @chan: Driver specific channel struct pointer
- */
-static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
-{
-       struct xilinx_dma_tx_descriptor *head_desc, *tail_desc;
-       struct xilinx_axidma_tx_segment *tail_segment, *old_head, *new_head;
-       u32 reg;
-
-       if (chan->err)
-               return;
-
-       if (list_empty(&chan->pending_list))
-               return;
-
-       /* If it is SG mode and hardware is busy, cannot submit */
-       if (chan->has_sg && xilinx_dma_is_running(chan) &&
-           !xilinx_dma_is_idle(chan)) {
-               dev_dbg(chan->dev, "DMA controller still busy\n");
-               return;
-       }
-
-       head_desc = list_first_entry(&chan->pending_list,
-                                    struct xilinx_dma_tx_descriptor, node);
-       tail_desc = list_last_entry(&chan->pending_list,
-                                   struct xilinx_dma_tx_descriptor, node);
-       tail_segment = list_last_entry(&tail_desc->segments,
-                                      struct xilinx_axidma_tx_segment, node);
-
-       old_head = list_first_entry(&head_desc->segments,
-                               struct xilinx_axidma_tx_segment, node);
-       new_head = chan->seg_v;
-       /* Copy Buffer Descriptor fields. */
-       new_head->hw = old_head->hw;
-
-       /* Swap and save new reserve */
-       list_replace_init(&old_head->node, &new_head->node);
-       chan->seg_v = old_head;
-
-       tail_segment->hw.next_desc = chan->seg_v->phys;
-       head_desc->async_tx.phys = new_head->phys;
-
-       reg = dma_ctrl_read(chan, XILINX_DMA_REG_DMACR);
-
-       if (chan->desc_pendingcount <= XILINX_DMA_COALESCE_MAX) {
-               reg &= ~XILINX_DMA_CR_COALESCE_MAX;
-               reg |= chan->desc_pendingcount <<
-                                 XILINX_DMA_CR_COALESCE_SHIFT;
-               dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
-       }
-
-       if (chan->has_sg)
-               dma_ctrl_write(chan, XILINX_DMA_REG_CURDESC,
-                              head_desc->async_tx.phys);
-
-       xilinx_dma_start(chan);
-
-       if (chan->err)
-               return;
-
-       /* Start the transfer */
-       if (chan->has_sg) {
-               dma_ctrl_write(chan, XILINX_DMA_REG_TAILDESC,
-                              tail_segment->phys);
-       } else {
-               struct xilinx_axidma_tx_segment *segment;
-               struct xilinx_axidma_desc_hw *hw;
-
-               segment = list_first_entry(&head_desc->segments,
-                                          struct xilinx_axidma_tx_segment,
-                                          node);
-               hw = &segment->hw;
-
-               dma_ctrl_write(chan, XILINX_DMA_REG_SRCDSTADDR, hw->buf_addr);
-
-               /* Start the transfer */
-               dma_ctrl_write(chan, XILINX_DMA_REG_BTT,
-                              hw->control & XILINX_DMA_MAX_TRANS_LEN);
-       }
-
-       list_splice_tail_init(&chan->pending_list, &chan->active_list);
-       chan->desc_pendingcount = 0;
-}
-
-/**
- * xilinx_dma_issue_pending - Issue pending transactions
- * @dchan: DMA channel
- */
-static void xilinx_dma_issue_pending(struct dma_chan *dchan)
-{
-       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
-       unsigned long flags;
-
-       spin_lock_irqsave(&chan->lock, flags);
-       chan->start_transfer(chan);
-       spin_unlock_irqrestore(&chan->lock, flags);
-}
-
-/**
- * xilinx_dma_complete_descriptor - Mark the active descriptor as complete
- * @chan : xilinx DMA channel
- *
- * CONTEXT: hardirq
- */
-static void xilinx_dma_complete_descriptor(struct xilinx_dma_chan *chan)
-{
-       struct xilinx_dma_tx_descriptor *desc, *next;
-
-       /* This function was invoked with lock held */
-       if (list_empty(&chan->active_list))
-               return;
-
-       list_for_each_entry_safe(desc, next, &chan->active_list, node) {
-               list_del(&desc->node);
-               dma_cookie_complete(&desc->async_tx);
-               list_add_tail(&desc->node, &chan->done_list);
-       }
-}
-
-/**
- * xilinx_dma_reset - Reset DMA channel
- * @chan: Driver specific DMA channel
- *
- * Return: '0' on success and failure value on error
- */
-static int xilinx_dma_reset(struct xilinx_dma_chan *chan)
-{
-       int err;
-       u32 tmp;
-
-       dma_ctrl_set(chan, XILINX_DMA_REG_DMACR, XILINX_DMA_DMACR_RESET);
-
-       /* Wait for the hardware to finish reset */
-       err = xilinx_dma_poll_timeout(chan, XILINX_DMA_REG_DMACR, tmp,
-                                     !(tmp & XILINX_DMA_DMACR_RESET), 0,
-                                     XILINX_DMA_LOOP_COUNT);
-
-       if (err) {
-               dev_err(chan->dev, "reset timeout, cr %x, sr %x\n",
-                       dma_ctrl_read(chan, XILINX_DMA_REG_DMACR),
-                       dma_ctrl_read(chan, XILINX_DMA_REG_DMASR));
-               return -ETIMEDOUT;
-       }
-
-       chan->err = false;
-
-       return err;
-}
-
-/**
- * xilinx_dma_chan_reset - Reset DMA channel and enable interrupts
- * @chan: Driver specific DMA channel
- *
- * Return: '0' on success and failure value on error
- */
-static int xilinx_dma_chan_reset(struct xilinx_dma_chan *chan)
-{
-       int err;
-
-       /* Reset VDMA */
-       err = xilinx_dma_reset(chan);
-       if (err)
-               return err;
-
-       /* Enable interrupts */
-       dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
-                     XILINX_DMA_DMAXR_ALL_IRQ_MASK);
-
-       return 0;
-}
-
-/**
- * xilinx_dma_irq_handler - DMA Interrupt handler
- * @irq: IRQ number
- * @data: Pointer to the Xilinx DMA channel structure
- *
- * Return: IRQ_HANDLED/IRQ_NONE
- */
-static irqreturn_t xilinx_dma_irq_handler(int irq, void *data)
-{
-       struct xilinx_dma_chan *chan = data;
-       u32 status;
-
-       /* Read the status and ack the interrupts. */
-       status = dma_ctrl_read(chan, XILINX_DMA_REG_DMASR);
-       if (!(status & XILINX_DMA_DMAXR_ALL_IRQ_MASK))
-               return IRQ_NONE;
-
-       dma_ctrl_write(chan, XILINX_DMA_REG_DMASR,
-                       status & XILINX_DMA_DMAXR_ALL_IRQ_MASK);
-
-       if (status & XILINX_DMA_DMASR_ERR_IRQ) {
-               /*
-                * An error occurred. If C_FLUSH_ON_FSYNC is enabled and the
-                * error is recoverable, ignore it. Otherwise flag the error.
-                *
-                * Only recoverable errors can be cleared in the DMASR register,
-                * make sure not to write to other error bits to 1.
-                */
-               u32 errors = status & XILINX_DMA_DMASR_ALL_ERR_MASK;
-
-               dma_ctrl_write(chan, XILINX_DMA_REG_DMASR,
-                               errors & XILINX_DMA_DMASR_ERR_RECOVER_MASK);
-
-               if (!chan->flush_on_fsync ||
-                   (errors & ~XILINX_DMA_DMASR_ERR_RECOVER_MASK)) {
-                       dev_err(chan->dev,
-                               "Channel %p has errors %x, cdr %x tdr %x\n",
-                               chan, errors,
-                               dma_ctrl_read(chan, XILINX_DMA_REG_CURDESC),
-                               dma_ctrl_read(chan, XILINX_DMA_REG_TAILDESC));
-                       chan->err = true;
-               }
-       }
-
-       if (status & XILINX_DMA_DMASR_DLY_CNT_IRQ) {
-               /*
-                * Device takes too long to do the transfer when user requires
-                * responsiveness.
-                */
-               dev_dbg(chan->dev, "Inter-packet latency too long\n");
-       }
-
-       if (status & XILINX_DMA_DMASR_FRM_CNT_IRQ) {
-               spin_lock(&chan->lock);
-               xilinx_dma_complete_descriptor(chan);
-               chan->start_transfer(chan);
-               spin_unlock(&chan->lock);
-       }
-
-       tasklet_schedule(&chan->tasklet);
-       return IRQ_HANDLED;
-}
-
-/**
- * append_desc_queue - Queuing descriptor
- * @chan: Driver specific dma channel
- * @desc: dma transaction descriptor
- */
-static void append_desc_queue(struct xilinx_dma_chan *chan,
-                             struct xilinx_dma_tx_descriptor *desc)
-{
-       struct xilinx_vdma_tx_segment *tail_segment;
-       struct xilinx_dma_tx_descriptor *tail_desc;
-       struct xilinx_axidma_tx_segment *axidma_tail_segment;
-       struct xilinx_cdma_tx_segment *cdma_tail_segment;
-
-       if (list_empty(&chan->pending_list))
-               goto append;
-
-       /*
-        * Add the hardware descriptor to the chain of hardware descriptors
-        * that already exists in memory.
-        */
-       tail_desc = list_last_entry(&chan->pending_list,
-                                   struct xilinx_dma_tx_descriptor, node);
-       if (chan->xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
-               tail_segment = list_last_entry(&tail_desc->segments,
-                                              struct xilinx_vdma_tx_segment,
-                                              node);
-               tail_segment->hw.next_desc = (u32)desc->async_tx.phys;
-       } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
-               cdma_tail_segment = list_last_entry(&tail_desc->segments,
-                                               struct xilinx_cdma_tx_segment,
-                                               node);
-               cdma_tail_segment->hw.next_desc = (u32)desc->async_tx.phys;
-       } else {
-               axidma_tail_segment = list_last_entry(&tail_desc->segments,
-                                              struct xilinx_axidma_tx_segment,
-                                              node);
-               axidma_tail_segment->hw.next_desc = (u32)desc->async_tx.phys;
-       }
-
-       /*
-        * Add the software descriptor and all children to the list
-        * of pending transactions
-        */
-append:
-       list_add_tail(&desc->node, &chan->pending_list);
-       chan->desc_pendingcount++;
-
-       if (chan->has_sg && (chan->xdev->dma_config->dmatype == XDMA_TYPE_VDMA)
-           && unlikely(chan->desc_pendingcount > chan->num_frms)) {
-               dev_dbg(chan->dev, "desc pendingcount is too high\n");
-               chan->desc_pendingcount = chan->num_frms;
-       }
-}
-
-/**
- * xilinx_dma_tx_submit - Submit DMA transaction
- * @tx: Async transaction descriptor
- *
- * Return: cookie value on success and failure value on error
- */
-static dma_cookie_t xilinx_dma_tx_submit(struct dma_async_tx_descriptor *tx)
-{
-       struct xilinx_dma_tx_descriptor *desc = to_dma_tx_descriptor(tx);
-       struct xilinx_dma_chan *chan = to_xilinx_chan(tx->chan);
-       dma_cookie_t cookie;
-       unsigned long flags;
-       int err;
-
-       if (chan->err) {
-               /*
-                * If reset fails, need to hard reset the system.
-                * Channel is no longer functional
-                */
-               err = xilinx_dma_chan_reset(chan);
-               if (err < 0)
-                       return err;
-       }
-
-       spin_lock_irqsave(&chan->lock, flags);
-
-       cookie = dma_cookie_assign(tx);
-
-       /* Put this transaction onto the tail of the pending queue */
-       append_desc_queue(chan, desc);
-
-       spin_unlock_irqrestore(&chan->lock, flags);
-
-       return cookie;
-}
-
-/**
- * xilinx_vdma_dma_prep_interleaved - prepare a descriptor for a
- *     DMA_SLAVE transaction
- * @dchan: DMA channel
- * @xt: Interleaved template pointer
- * @flags: transfer ack flags
- *
- * Return: Async transaction descriptor on success and NULL on failure
- */
-static struct dma_async_tx_descriptor *
-xilinx_vdma_dma_prep_interleaved(struct dma_chan *dchan,
-                                struct dma_interleaved_template *xt,
-                                unsigned long flags)
-{
-       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
-       struct xilinx_dma_tx_descriptor *desc;
-       struct xilinx_vdma_tx_segment *segment, *prev = NULL;
-       struct xilinx_vdma_desc_hw *hw;
-
-       if (!is_slave_direction(xt->dir))
-               return NULL;
-
-       if (!xt->numf || !xt->sgl[0].size)
-               return NULL;
-
-       if (xt->frame_size != 1)
-               return NULL;
-
-       /* Allocate a transaction descriptor. */
-       desc = xilinx_dma_alloc_tx_descriptor(chan);
-       if (!desc)
-               return NULL;
-
-       dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
-       desc->async_tx.tx_submit = xilinx_dma_tx_submit;
-       async_tx_ack(&desc->async_tx);
-
-       /* Allocate the link descriptor from DMA pool */
-       segment = xilinx_vdma_alloc_tx_segment(chan);
-       if (!segment)
-               goto error;
-
-       /* Fill in the hardware descriptor */
-       hw = &segment->hw;
-       hw->vsize = xt->numf;
-       hw->hsize = xt->sgl[0].size;
-       hw->stride = (xt->sgl[0].icg + xt->sgl[0].size) <<
-                       XILINX_DMA_FRMDLY_STRIDE_STRIDE_SHIFT;
-       hw->stride |= chan->config.frm_dly <<
-                       XILINX_DMA_FRMDLY_STRIDE_FRMDLY_SHIFT;
-
-       if (xt->dir != DMA_MEM_TO_DEV) {
-               if (chan->ext_addr) {
-                       hw->buf_addr = lower_32_bits(xt->dst_start);
-                       hw->buf_addr_msb = upper_32_bits(xt->dst_start);
-               } else {
-                       hw->buf_addr = xt->dst_start;
-               }
-       } else {
-               if (chan->ext_addr) {
-                       hw->buf_addr = lower_32_bits(xt->src_start);
-                       hw->buf_addr_msb = upper_32_bits(xt->src_start);
-               } else {
-                       hw->buf_addr = xt->src_start;
-               }
-       }
-
-       /* Insert the segment into the descriptor segments list. */
-       list_add_tail(&segment->node, &desc->segments);
-
-       prev = segment;
-
-       /* Link the last hardware descriptor with the first. */
-       segment = list_first_entry(&desc->segments,
-                                  struct xilinx_vdma_tx_segment, node);
-       desc->async_tx.phys = segment->phys;
-
-       return &desc->async_tx;
-
-error:
-       xilinx_dma_free_tx_descriptor(chan, desc);
-       return NULL;
-}
-
-/**
- * xilinx_cdma_prep_memcpy - prepare descriptors for a memcpy transaction
- * @dchan: DMA channel
- * @dma_dst: destination address
- * @dma_src: source address
- * @len: transfer length
- * @flags: transfer ack flags
- *
- * Return: Async transaction descriptor on success and NULL on failure
- */
-static struct dma_async_tx_descriptor *
-xilinx_cdma_prep_memcpy(struct dma_chan *dchan, dma_addr_t dma_dst,
-                       dma_addr_t dma_src, size_t len, unsigned long flags)
-{
-       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
-       struct xilinx_dma_tx_descriptor *desc;
-       struct xilinx_cdma_tx_segment *segment, *prev;
-       struct xilinx_cdma_desc_hw *hw;
-
-       if (!len || len > XILINX_DMA_MAX_TRANS_LEN)
-               return NULL;
-
-       desc = xilinx_dma_alloc_tx_descriptor(chan);
-       if (!desc)
-               return NULL;
-
-       dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
-       desc->async_tx.tx_submit = xilinx_dma_tx_submit;
-
-       /* Allocate the link descriptor from DMA pool */
-       segment = xilinx_cdma_alloc_tx_segment(chan);
-       if (!segment)
-               goto error;
-
-       hw = &segment->hw;
-       hw->control = len;
-       hw->src_addr = dma_src;
-       hw->dest_addr = dma_dst;
-
-       /* Fill the previous next descriptor with current */
-       prev = list_last_entry(&desc->segments,
-                              struct xilinx_cdma_tx_segment, node);
-       prev->hw.next_desc = segment->phys;
-
-       /* Insert the segment into the descriptor segments list. */
-       list_add_tail(&segment->node, &desc->segments);
-
-       prev = segment;
-
-       /* Link the last hardware descriptor with the first. */
-       segment = list_first_entry(&desc->segments,
-                               struct xilinx_cdma_tx_segment, node);
-       desc->async_tx.phys = segment->phys;
-       prev->hw.next_desc = segment->phys;
-
-       return &desc->async_tx;
-
-error:
-       xilinx_dma_free_tx_descriptor(chan, desc);
-       return NULL;
-}
-
-/**
- * xilinx_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
- * @dchan: DMA channel
- * @sgl: scatterlist to transfer to/from
- * @sg_len: number of entries in @scatterlist
- * @direction: DMA direction
- * @flags: transfer ack flags
- * @context: APP words of the descriptor
- *
- * Return: Async transaction descriptor on success and NULL on failure
- */
-static struct dma_async_tx_descriptor *xilinx_dma_prep_slave_sg(
-       struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len,
-       enum dma_transfer_direction direction, unsigned long flags,
-       void *context)
-{
-       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
-       struct xilinx_dma_tx_descriptor *desc;
-       struct xilinx_axidma_tx_segment *segment = NULL, *prev = NULL;
-       u32 *app_w = (u32 *)context;
-       struct scatterlist *sg;
-       size_t copy;
-       size_t sg_used;
-       unsigned int i;
-
-       if (!is_slave_direction(direction))
-               return NULL;
-
-       /* Allocate a transaction descriptor. */
-       desc = xilinx_dma_alloc_tx_descriptor(chan);
-       if (!desc)
-               return NULL;
-
-       dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
-       desc->async_tx.tx_submit = xilinx_dma_tx_submit;
-
-       /* Build transactions using information in the scatter gather list */
-       for_each_sg(sgl, sg, sg_len, i) {
-               sg_used = 0;
-
-               /* Loop until the entire scatterlist entry is used */
-               while (sg_used < sg_dma_len(sg)) {
-                       struct xilinx_axidma_desc_hw *hw;
-
-                       /* Get a free segment */
-                       segment = xilinx_axidma_alloc_tx_segment(chan);
-                       if (!segment)
-                               goto error;
-
-                       /*
-                        * Calculate the maximum number of bytes to transfer,
-                        * making sure it is less than the hw limit
-                        */
-                       copy = min_t(size_t, sg_dma_len(sg) - sg_used,
-                                    XILINX_DMA_MAX_TRANS_LEN);
-                       hw = &segment->hw;
-
-                       /* Fill in the descriptor */
-                       hw->buf_addr = sg_dma_address(sg) + sg_used;
-
-                       hw->control = copy;
-
-                       if (chan->direction == DMA_MEM_TO_DEV) {
-                               if (app_w)
-                                       memcpy(hw->app, app_w, sizeof(u32) *
-                                              XILINX_DMA_NUM_APP_WORDS);
-                       }
-
-                       if (prev)
-                               prev->hw.next_desc = segment->phys;
-
-                       prev = segment;
-                       sg_used += copy;
-
-                       /*
-                        * Insert the segment into the descriptor segments
-                        * list.
-                        */
-                       list_add_tail(&segment->node, &desc->segments);
-               }
-       }
-
-       segment = list_first_entry(&desc->segments,
-                                  struct xilinx_axidma_tx_segment, node);
-       desc->async_tx.phys = segment->phys;
-       prev->hw.next_desc = segment->phys;
-
-       /* For the last DMA_MEM_TO_DEV transfer, set EOP */
-       if (chan->direction == DMA_MEM_TO_DEV) {
-               segment->hw.control |= XILINX_DMA_BD_SOP;
-               segment = list_last_entry(&desc->segments,
-                                         struct xilinx_axidma_tx_segment,
-                                         node);
-               segment->hw.control |= XILINX_DMA_BD_EOP;
-       }
-
-       return &desc->async_tx;
-
-error:
-       xilinx_dma_free_tx_descriptor(chan, desc);
-       return NULL;
-}
-
-/**
- * xilinx_dma_terminate_all - Halt the channel and free descriptors
- * @chan: Driver specific DMA Channel pointer
- */
-static int xilinx_dma_terminate_all(struct dma_chan *dchan)
-{
-       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
-
-       /* Halt the DMA engine */
-       xilinx_dma_halt(chan);
-
-       /* Remove and free all of the descriptors in the lists */
-       xilinx_dma_free_descriptors(chan);
-
-       return 0;
-}
-
-/**
- * xilinx_dma_channel_set_config - Configure VDMA channel
- * Run-time configuration for Axi VDMA, supports:
- * . halt the channel
- * . configure interrupt coalescing and inter-packet delay threshold
- * . start/stop parking
- * . enable genlock
- *
- * @dchan: DMA channel
- * @cfg: VDMA device configuration pointer
- *
- * Return: '0' on success and failure value on error
- */
-int xilinx_vdma_channel_set_config(struct dma_chan *dchan,
-                                       struct xilinx_vdma_config *cfg)
-{
-       struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
-       u32 dmacr;
-
-       if (cfg->reset)
-               return xilinx_dma_chan_reset(chan);
-
-       dmacr = dma_ctrl_read(chan, XILINX_DMA_REG_DMACR);
-
-       chan->config.frm_dly = cfg->frm_dly;
-       chan->config.park = cfg->park;
-
-       /* genlock settings */
-       chan->config.gen_lock = cfg->gen_lock;
-       chan->config.master = cfg->master;
-
-       if (cfg->gen_lock && chan->genlock) {
-               dmacr |= XILINX_DMA_DMACR_GENLOCK_EN;
-               dmacr |= cfg->master << XILINX_DMA_DMACR_MASTER_SHIFT;
-       }
-
-       chan->config.frm_cnt_en = cfg->frm_cnt_en;
-       if (cfg->park)
-               chan->config.park_frm = cfg->park_frm;
-       else
-               chan->config.park_frm = -1;
-
-       chan->config.coalesc = cfg->coalesc;
-       chan->config.delay = cfg->delay;
-
-       if (cfg->coalesc <= XILINX_DMA_DMACR_FRAME_COUNT_MAX) {
-               dmacr |= cfg->coalesc << XILINX_DMA_DMACR_FRAME_COUNT_SHIFT;
-               chan->config.coalesc = cfg->coalesc;
-       }
-
-       if (cfg->delay <= XILINX_DMA_DMACR_DELAY_MAX) {
-               dmacr |= cfg->delay << XILINX_DMA_DMACR_DELAY_SHIFT;
-               chan->config.delay = cfg->delay;
-       }
-
-       /* FSync Source selection */
-       dmacr &= ~XILINX_DMA_DMACR_FSYNCSRC_MASK;
-       dmacr |= cfg->ext_fsync << XILINX_DMA_DMACR_FSYNCSRC_SHIFT;
-
-       dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, dmacr);
-
-       return 0;
-}
-EXPORT_SYMBOL(xilinx_vdma_channel_set_config);
-
-/* -----------------------------------------------------------------------------
- * Probe and remove
- */
-
-/**
- * xilinx_dma_chan_remove - Per Channel remove function
- * @chan: Driver specific DMA channel
- */
-static void xilinx_dma_chan_remove(struct xilinx_dma_chan *chan)
-{
-       /* Disable all interrupts */
-       dma_ctrl_clr(chan, XILINX_DMA_REG_DMACR,
-                     XILINX_DMA_DMAXR_ALL_IRQ_MASK);
-
-       if (chan->irq > 0)
-               free_irq(chan->irq, chan);
-
-       tasklet_kill(&chan->tasklet);
-
-       list_del(&chan->common.device_node);
-}
-
-static int axidma_clk_init(struct platform_device *pdev, struct clk **axi_clk,
-                           struct clk **tx_clk, struct clk **rx_clk,
-                           struct clk **sg_clk, struct clk **tmp_clk)
-{
-       int err;
-
-       *tmp_clk = NULL;
-
-       *axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk");
-       if (IS_ERR(*axi_clk)) {
-               err = PTR_ERR(*axi_clk);
-               dev_err(&pdev->dev, "failed to get axi_aclk (%u)\n", err);
-               return err;
-       }
-
-       *tx_clk = devm_clk_get(&pdev->dev, "m_axi_mm2s_aclk");
-       if (IS_ERR(*tx_clk))
-               *tx_clk = NULL;
-
-       *rx_clk = devm_clk_get(&pdev->dev, "m_axi_s2mm_aclk");
-       if (IS_ERR(*rx_clk))
-               *rx_clk = NULL;
-
-       *sg_clk = devm_clk_get(&pdev->dev, "m_axi_sg_aclk");
-       if (IS_ERR(*sg_clk))
-               *sg_clk = NULL;
-
-       err = clk_prepare_enable(*axi_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err);
-               return err;
-       }
-
-       err = clk_prepare_enable(*tx_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err);
-               goto err_disable_axiclk;
-       }
-
-       err = clk_prepare_enable(*rx_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable rx_clk (%u)\n", err);
-               goto err_disable_txclk;
-       }
-
-       err = clk_prepare_enable(*sg_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable sg_clk (%u)\n", err);
-               goto err_disable_rxclk;
-       }
-
-       return 0;
-
-err_disable_rxclk:
-       clk_disable_unprepare(*rx_clk);
-err_disable_txclk:
-       clk_disable_unprepare(*tx_clk);
-err_disable_axiclk:
-       clk_disable_unprepare(*axi_clk);
-
-       return err;
-}
-
-static int axicdma_clk_init(struct platform_device *pdev, struct clk **axi_clk,
-                           struct clk **dev_clk, struct clk **tmp_clk,
-                           struct clk **tmp1_clk, struct clk **tmp2_clk)
-{
-       int err;
-
-       *tmp_clk = NULL;
-       *tmp1_clk = NULL;
-       *tmp2_clk = NULL;
-
-       *axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk");
-       if (IS_ERR(*axi_clk)) {
-               err = PTR_ERR(*axi_clk);
-               dev_err(&pdev->dev, "failed to get axi_clk (%u)\n", err);
-               return err;
-       }
-
-       *dev_clk = devm_clk_get(&pdev->dev, "m_axi_aclk");
-       if (IS_ERR(*dev_clk)) {
-               err = PTR_ERR(*dev_clk);
-               dev_err(&pdev->dev, "failed to get dev_clk (%u)\n", err);
-               return err;
-       }
-
-       err = clk_prepare_enable(*axi_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err);
-               return err;
-       }
-
-       err = clk_prepare_enable(*dev_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable dev_clk (%u)\n", err);
-               goto err_disable_axiclk;
-       }
-
-       return 0;
-
-err_disable_axiclk:
-       clk_disable_unprepare(*axi_clk);
-
-       return err;
-}
-
-static int axivdma_clk_init(struct platform_device *pdev, struct clk **axi_clk,
-                           struct clk **tx_clk, struct clk **txs_clk,
-                           struct clk **rx_clk, struct clk **rxs_clk)
-{
-       int err;
-
-       *axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk");
-       if (IS_ERR(*axi_clk)) {
-               err = PTR_ERR(*axi_clk);
-               dev_err(&pdev->dev, "failed to get axi_aclk (%u)\n", err);
-               return err;
-       }
-
-       *tx_clk = devm_clk_get(&pdev->dev, "m_axi_mm2s_aclk");
-       if (IS_ERR(*tx_clk))
-               *tx_clk = NULL;
-
-       *txs_clk = devm_clk_get(&pdev->dev, "m_axis_mm2s_aclk");
-       if (IS_ERR(*txs_clk))
-               *txs_clk = NULL;
-
-       *rx_clk = devm_clk_get(&pdev->dev, "m_axi_s2mm_aclk");
-       if (IS_ERR(*rx_clk))
-               *rx_clk = NULL;
-
-       *rxs_clk = devm_clk_get(&pdev->dev, "s_axis_s2mm_aclk");
-       if (IS_ERR(*rxs_clk))
-               *rxs_clk = NULL;
-
-       err = clk_prepare_enable(*axi_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err);
-               return err;
-       }
-
-       err = clk_prepare_enable(*tx_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err);
-               goto err_disable_axiclk;
-       }
-
-       err = clk_prepare_enable(*txs_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable txs_clk (%u)\n", err);
-               goto err_disable_txclk;
-       }
-
-       err = clk_prepare_enable(*rx_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable rx_clk (%u)\n", err);
-               goto err_disable_txsclk;
-       }
-
-       err = clk_prepare_enable(*rxs_clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable rxs_clk (%u)\n", err);
-               goto err_disable_rxclk;
-       }
-
-       return 0;
-
-err_disable_rxclk:
-       clk_disable_unprepare(*rx_clk);
-err_disable_txsclk:
-       clk_disable_unprepare(*txs_clk);
-err_disable_txclk:
-       clk_disable_unprepare(*tx_clk);
-err_disable_axiclk:
-       clk_disable_unprepare(*axi_clk);
-
-       return err;
-}
-
-static void xdma_disable_allclks(struct xilinx_dma_device *xdev)
-{
-       clk_disable_unprepare(xdev->rxs_clk);
-       clk_disable_unprepare(xdev->rx_clk);
-       clk_disable_unprepare(xdev->txs_clk);
-       clk_disable_unprepare(xdev->tx_clk);
-       clk_disable_unprepare(xdev->axi_clk);
-}
-
-/**
- * xilinx_dma_chan_probe - Per Channel Probing
- * It get channel features from the device tree entry and
- * initialize special channel handling routines
- *
- * @xdev: Driver specific device structure
- * @node: Device node
- *
- * Return: '0' on success and failure value on error
- */
-static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
-                                 struct device_node *node)
-{
-       struct xilinx_dma_chan *chan;
-       bool has_dre = false;
-       u32 value, width;
-       int err;
-
-       /* Allocate and initialize the channel structure */
-       chan = devm_kzalloc(xdev->dev, sizeof(*chan), GFP_KERNEL);
-       if (!chan)
-               return -ENOMEM;
-
-       chan->dev = xdev->dev;
-       chan->xdev = xdev;
-       chan->has_sg = xdev->has_sg;
-       chan->desc_pendingcount = 0x0;
-       chan->ext_addr = xdev->ext_addr;
-
-       spin_lock_init(&chan->lock);
-       INIT_LIST_HEAD(&chan->pending_list);
-       INIT_LIST_HEAD(&chan->done_list);
-       INIT_LIST_HEAD(&chan->active_list);
-
-       /* Retrieve the channel properties from the device tree */
-       has_dre = of_property_read_bool(node, "xlnx,include-dre");
-
-       chan->genlock = of_property_read_bool(node, "xlnx,genlock-mode");
-
-       err = of_property_read_u32(node, "xlnx,datawidth", &value);
-       if (err) {
-               dev_err(xdev->dev, "missing xlnx,datawidth property\n");
-               return err;
-       }
-       width = value >> 3; /* Convert bits to bytes */
-
-       /* If data width is greater than 8 bytes, DRE is not in hw */
-       if (width > 8)
-               has_dre = false;
-
-       if (!has_dre)
-               xdev->common.copy_align = fls(width - 1);
-
-       if (of_device_is_compatible(node, "xlnx,axi-vdma-mm2s-channel")) {
-               chan->direction = DMA_MEM_TO_DEV;
-               chan->id = 0;
-
-               chan->ctrl_offset = XILINX_DMA_MM2S_CTRL_OFFSET;
-               if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
-                       chan->desc_offset = XILINX_VDMA_MM2S_DESC_OFFSET;
-
-                       if (xdev->flush_on_fsync == XILINX_DMA_FLUSH_BOTH ||
-                           xdev->flush_on_fsync == XILINX_DMA_FLUSH_MM2S)
-                               chan->flush_on_fsync = true;
-               }
-       } else if (of_device_is_compatible(node,
-                                           "xlnx,axi-vdma-s2mm-channel")) {
-               chan->direction = DMA_DEV_TO_MEM;
-               chan->id = 1;
-
-               chan->ctrl_offset = XILINX_DMA_S2MM_CTRL_OFFSET;
-               if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
-                       chan->desc_offset = XILINX_VDMA_S2MM_DESC_OFFSET;
-
-                       if (xdev->flush_on_fsync == XILINX_DMA_FLUSH_BOTH ||
-                           xdev->flush_on_fsync == XILINX_DMA_FLUSH_S2MM)
-                               chan->flush_on_fsync = true;
-               }
-       } else {
-               dev_err(xdev->dev, "Invalid channel compatible node\n");
-               return -EINVAL;
-       }
-
-       /* Request the interrupt */
-       chan->irq = irq_of_parse_and_map(node, 0);
-       err = request_irq(chan->irq, xilinx_dma_irq_handler, IRQF_SHARED,
-                         "xilinx-dma-controller", chan);
-       if (err) {
-               dev_err(xdev->dev, "unable to request IRQ %d\n", chan->irq);
-               return err;
-       }
-
-       if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA)
-               chan->start_transfer = xilinx_dma_start_transfer;
-       else if (xdev->dma_config->dmatype == XDMA_TYPE_CDMA)
-               chan->start_transfer = xilinx_cdma_start_transfer;
-       else
-               chan->start_transfer = xilinx_vdma_start_transfer;
-
-       /* Initialize the tasklet */
-       tasklet_init(&chan->tasklet, xilinx_dma_do_tasklet,
-                       (unsigned long)chan);
-
-       /*
-        * Initialize the DMA channel and add it to the DMA engine channels
-        * list.
-        */
-       chan->common.device = &xdev->common;
-
-       list_add_tail(&chan->common.device_node, &xdev->common.channels);
-       xdev->chan[chan->id] = chan;
-
-       /* Reset the channel */
-       err = xilinx_dma_chan_reset(chan);
-       if (err < 0) {
-               dev_err(xdev->dev, "Reset channel failed\n");
-               return err;
-       }
-
-       return 0;
-}
-
-/**
- * of_dma_xilinx_xlate - Translation function
- * @dma_spec: Pointer to DMA specifier as found in the device tree
- * @ofdma: Pointer to DMA controller data
- *
- * Return: DMA channel pointer on success and NULL on error
- */
-static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec,
-                                               struct of_dma *ofdma)
-{
-       struct xilinx_dma_device *xdev = ofdma->of_dma_data;
-       int chan_id = dma_spec->args[0];
-
-       if (chan_id >= XILINX_DMA_MAX_CHANS_PER_DEVICE || !xdev->chan[chan_id])
-               return NULL;
-
-       return dma_get_slave_channel(&xdev->chan[chan_id]->common);
-}
-
-static const struct xilinx_dma_config axidma_config = {
-       .dmatype = XDMA_TYPE_AXIDMA,
-       .clk_init = axidma_clk_init,
-};
-
-static const struct xilinx_dma_config axicdma_config = {
-       .dmatype = XDMA_TYPE_CDMA,
-       .clk_init = axicdma_clk_init,
-};
-
-static const struct xilinx_dma_config axivdma_config = {
-       .dmatype = XDMA_TYPE_VDMA,
-       .clk_init = axivdma_clk_init,
-};
-
-static const struct of_device_id xilinx_dma_of_ids[] = {
-       { .compatible = "xlnx,axi-dma-1.00.a", .data = &axidma_config },
-       { .compatible = "xlnx,axi-cdma-1.00.a", .data = &axicdma_config },
-       { .compatible = "xlnx,axi-vdma-1.00.a", .data = &axivdma_config },
-       {}
-};
-MODULE_DEVICE_TABLE(of, xilinx_dma_of_ids);
-
-/**
- * xilinx_dma_probe - Driver probe function
- * @pdev: Pointer to the platform_device structure
- *
- * Return: '0' on success and failure value on error
- */
-static int xilinx_dma_probe(struct platform_device *pdev)
-{
-       int (*clk_init)(struct platform_device *, struct clk **, struct clk **,
-                       struct clk **, struct clk **, struct clk **)
-                                       = axivdma_clk_init;
-       struct device_node *node = pdev->dev.of_node;
-       struct xilinx_dma_device *xdev;
-       struct device_node *child, *np = pdev->dev.of_node;
-       struct resource *io;
-       u32 num_frames, addr_width;
-       int i, err;
-
-       /* Allocate and initialize the DMA engine structure */
-       xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL);
-       if (!xdev)
-               return -ENOMEM;
-
-       xdev->dev = &pdev->dev;
-       if (np) {
-               const struct of_device_id *match;
-
-               match = of_match_node(xilinx_dma_of_ids, np);
-               if (match && match->data) {
-                       xdev->dma_config = match->data;
-                       clk_init = xdev->dma_config->clk_init;
-               }
-       }
-
-       err = clk_init(pdev, &xdev->axi_clk, &xdev->tx_clk, &xdev->txs_clk,
-                      &xdev->rx_clk, &xdev->rxs_clk);
-       if (err)
-               return err;
-
-       /* Request and map I/O memory */
-       io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       xdev->regs = devm_ioremap_resource(&pdev->dev, io);
-       if (IS_ERR(xdev->regs))
-               return PTR_ERR(xdev->regs);
-
-       /* Retrieve the DMA engine properties from the device tree */
-       xdev->has_sg = of_property_read_bool(node, "xlnx,include-sg");
-
-       if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
-               err = of_property_read_u32(node, "xlnx,num-fstores",
-                                          &num_frames);
-               if (err < 0) {
-                       dev_err(xdev->dev,
-                               "missing xlnx,num-fstores property\n");
-                       return err;
-               }
-
-               err = of_property_read_u32(node, "xlnx,flush-fsync",
-                                          &xdev->flush_on_fsync);
-               if (err < 0)
-                       dev_warn(xdev->dev,
-                                "missing xlnx,flush-fsync property\n");
-       }
-
-       err = of_property_read_u32(node, "xlnx,addrwidth", &addr_width);
-       if (err < 0)
-               dev_warn(xdev->dev, "missing xlnx,addrwidth property\n");
-
-       if (addr_width > 32)
-               xdev->ext_addr = true;
-       else
-               xdev->ext_addr = false;
-
-       /* Set the dma mask bits */
-       dma_set_mask(xdev->dev, DMA_BIT_MASK(addr_width));
-
-       /* Initialize the DMA engine */
-       xdev->common.dev = &pdev->dev;
-
-       INIT_LIST_HEAD(&xdev->common.channels);
-       if (!(xdev->dma_config->dmatype == XDMA_TYPE_CDMA)) {
-               dma_cap_set(DMA_SLAVE, xdev->common.cap_mask);
-               dma_cap_set(DMA_PRIVATE, xdev->common.cap_mask);
-       }
-
-       xdev->common.device_alloc_chan_resources =
-                               xilinx_dma_alloc_chan_resources;
-       xdev->common.device_free_chan_resources =
-                               xilinx_dma_free_chan_resources;
-       xdev->common.device_terminate_all = xilinx_dma_terminate_all;
-       xdev->common.device_tx_status = xilinx_dma_tx_status;
-       xdev->common.device_issue_pending = xilinx_dma_issue_pending;
-       if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
-               xdev->common.device_prep_slave_sg = xilinx_dma_prep_slave_sg;
-               /* Residue calculation is supported by only AXI DMA */
-               xdev->common.residue_granularity =
-                                         DMA_RESIDUE_GRANULARITY_SEGMENT;
-       } else if (xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
-               dma_cap_set(DMA_MEMCPY, xdev->common.cap_mask);
-               xdev->common.device_prep_dma_memcpy = xilinx_cdma_prep_memcpy;
-       } else {
-               xdev->common.device_prep_interleaved_dma =
-                               xilinx_vdma_dma_prep_interleaved;
-       }
-
-       platform_set_drvdata(pdev, xdev);
-
-       /* Initialize the channels */
-       for_each_child_of_node(node, child) {
-               err = xilinx_dma_chan_probe(xdev, child);
-               if (err < 0)
-                       goto disable_clks;
-       }
-
-       if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
-               for (i = 0; i < XILINX_DMA_MAX_CHANS_PER_DEVICE; i++)
-                       if (xdev->chan[i])
-                               xdev->chan[i]->num_frms = num_frames;
-       }
-
-       /* Register the DMA engine with the core */
-       dma_async_device_register(&xdev->common);
-
-       err = of_dma_controller_register(node, of_dma_xilinx_xlate,
-                                        xdev);
-       if (err < 0) {
-               dev_err(&pdev->dev, "Unable to register DMA to DT\n");
-               dma_async_device_unregister(&xdev->common);
-               goto error;
-       }
-
-       dev_info(&pdev->dev, "Xilinx AXI VDMA Engine Driver Probed!!\n");
-
-       return 0;
-
-disable_clks:
-       xdma_disable_allclks(xdev);
-error:
-       for (i = 0; i < XILINX_DMA_MAX_CHANS_PER_DEVICE; i++)
-               if (xdev->chan[i])
-                       xilinx_dma_chan_remove(xdev->chan[i]);
-
-       return err;
-}
-
-/**
- * xilinx_dma_remove - Driver remove function
- * @pdev: Pointer to the platform_device structure
- *
- * Return: Always '0'
- */
-static int xilinx_dma_remove(struct platform_device *pdev)
-{
-       struct xilinx_dma_device *xdev = platform_get_drvdata(pdev);
-       int i;
-
-       of_dma_controller_free(pdev->dev.of_node);
-
-       dma_async_device_unregister(&xdev->common);
-
-       for (i = 0; i < XILINX_DMA_MAX_CHANS_PER_DEVICE; i++)
-               if (xdev->chan[i])
-                       xilinx_dma_chan_remove(xdev->chan[i]);
-
-       xdma_disable_allclks(xdev);
-
-       return 0;
-}
-
-static struct platform_driver xilinx_vdma_driver = {
-       .driver = {
-               .name = "xilinx-vdma",
-               .of_match_table = xilinx_dma_of_ids,
-       },
-       .probe = xilinx_dma_probe,
-       .remove = xilinx_dma_remove,
-};
-
-module_platform_driver(xilinx_vdma_driver);
-
-MODULE_AUTHOR("Xilinx, Inc.");
-MODULE_DESCRIPTION("Xilinx VDMA driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c
new file mode 100644 (file)
index 0000000..6d221e5
--- /dev/null
@@ -0,0 +1,1151 @@
+/*
+ * DMA driver for Xilinx ZynqMP DMA Engine
+ *
+ * Copyright (C) 2016 Xilinx, Inc. All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/bitops.h>
+#include <linux/dmapool.h>
+#include <linux/dma/xilinx_dma.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_dma.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+
+#include "../dmaengine.h"
+
+/* Register Offsets */
+#define ZYNQMP_DMA_ISR                 0x100
+#define ZYNQMP_DMA_IMR                 0x104
+#define ZYNQMP_DMA_IER                 0x108
+#define ZYNQMP_DMA_IDS                 0x10C
+#define ZYNQMP_DMA_CTRL0               0x110
+#define ZYNQMP_DMA_CTRL1               0x114
+#define ZYNQMP_DMA_DATA_ATTR           0x120
+#define ZYNQMP_DMA_DSCR_ATTR           0x124
+#define ZYNQMP_DMA_SRC_DSCR_WRD0       0x128
+#define ZYNQMP_DMA_SRC_DSCR_WRD1       0x12C
+#define ZYNQMP_DMA_SRC_DSCR_WRD2       0x130
+#define ZYNQMP_DMA_SRC_DSCR_WRD3       0x134
+#define ZYNQMP_DMA_DST_DSCR_WRD0       0x138
+#define ZYNQMP_DMA_DST_DSCR_WRD1       0x13C
+#define ZYNQMP_DMA_DST_DSCR_WRD2       0x140
+#define ZYNQMP_DMA_DST_DSCR_WRD3       0x144
+#define ZYNQMP_DMA_SRC_START_LSB       0x158
+#define ZYNQMP_DMA_SRC_START_MSB       0x15C
+#define ZYNQMP_DMA_DST_START_LSB       0x160
+#define ZYNQMP_DMA_DST_START_MSB       0x164
+#define ZYNQMP_DMA_RATE_CTRL           0x18C
+#define ZYNQMP_DMA_IRQ_SRC_ACCT                0x190
+#define ZYNQMP_DMA_IRQ_DST_ACCT                0x194
+#define ZYNQMP_DMA_CTRL2               0x200
+
+/* Interrupt registers bit field definitions */
+#define ZYNQMP_DMA_DONE                        BIT(10)
+#define ZYNQMP_DMA_AXI_WR_DATA         BIT(9)
+#define ZYNQMP_DMA_AXI_RD_DATA         BIT(8)
+#define ZYNQMP_DMA_AXI_RD_DST_DSCR     BIT(7)
+#define ZYNQMP_DMA_AXI_RD_SRC_DSCR     BIT(6)
+#define ZYNQMP_DMA_IRQ_DST_ACCT_ERR    BIT(5)
+#define ZYNQMP_DMA_IRQ_SRC_ACCT_ERR    BIT(4)
+#define ZYNQMP_DMA_BYTE_CNT_OVRFL      BIT(3)
+#define ZYNQMP_DMA_DST_DSCR_DONE       BIT(2)
+#define ZYNQMP_DMA_INV_APB             BIT(0)
+
+/* Control 0 register bit field definitions */
+#define ZYNQMP_DMA_OVR_FETCH           BIT(7)
+#define ZYNQMP_DMA_POINT_TYPE_SG       BIT(6)
+#define ZYNQMP_DMA_RATE_CTRL_EN                BIT(3)
+
+/* Control 1 register bit field definitions */
+#define ZYNQMP_DMA_SRC_ISSUE           GENMASK(4, 0)
+
+/* Data Attribute register bit field definitions */
+#define ZYNQMP_DMA_ARBURST             GENMASK(27, 26)
+#define ZYNQMP_DMA_ARCACHE             GENMASK(25, 22)
+#define ZYNQMP_DMA_ARCACHE_OFST                22
+#define ZYNQMP_DMA_ARQOS               GENMASK(21, 18)
+#define ZYNQMP_DMA_ARQOS_OFST          18
+#define ZYNQMP_DMA_ARLEN               GENMASK(17, 14)
+#define ZYNQMP_DMA_ARLEN_OFST          14
+#define ZYNQMP_DMA_AWBURST             GENMASK(13, 12)
+#define ZYNQMP_DMA_AWCACHE             GENMASK(11, 8)
+#define ZYNQMP_DMA_AWCACHE_OFST                8
+#define ZYNQMP_DMA_AWQOS               GENMASK(7, 4)
+#define ZYNQMP_DMA_AWQOS_OFST          4
+#define ZYNQMP_DMA_AWLEN               GENMASK(3, 0)
+#define ZYNQMP_DMA_AWLEN_OFST          0
+
+/* Descriptor Attribute register bit field definitions */
+#define ZYNQMP_DMA_AXCOHRNT            BIT(8)
+#define ZYNQMP_DMA_AXCACHE             GENMASK(7, 4)
+#define ZYNQMP_DMA_AXCACHE_OFST                4
+#define ZYNQMP_DMA_AXQOS               GENMASK(3, 0)
+#define ZYNQMP_DMA_AXQOS_OFST          0
+
+/* Control register 2 bit field definitions */
+#define ZYNQMP_DMA_ENABLE              BIT(0)
+
+/* Buffer Descriptor definitions */
+#define ZYNQMP_DMA_DESC_CTRL_STOP      0x10
+#define ZYNQMP_DMA_DESC_CTRL_COMP_INT  0x4
+#define ZYNQMP_DMA_DESC_CTRL_SIZE_256  0x2
+#define ZYNQMP_DMA_DESC_CTRL_COHRNT    0x1
+
+/* Interrupt Mask specific definitions */
+#define ZYNQMP_DMA_INT_ERR     (ZYNQMP_DMA_AXI_RD_DATA | \
+                               ZYNQMP_DMA_AXI_WR_DATA | \
+                               ZYNQMP_DMA_AXI_RD_DST_DSCR | \
+                               ZYNQMP_DMA_AXI_RD_SRC_DSCR | \
+                               ZYNQMP_DMA_INV_APB)
+#define ZYNQMP_DMA_INT_OVRFL   (ZYNQMP_DMA_BYTE_CNT_OVRFL | \
+                               ZYNQMP_DMA_IRQ_SRC_ACCT_ERR | \
+                               ZYNQMP_DMA_IRQ_DST_ACCT_ERR)
+#define ZYNQMP_DMA_INT_DONE    (ZYNQMP_DMA_DONE | ZYNQMP_DMA_DST_DSCR_DONE)
+#define ZYNQMP_DMA_INT_EN_DEFAULT_MASK (ZYNQMP_DMA_INT_DONE | \
+                                       ZYNQMP_DMA_INT_ERR | \
+                                       ZYNQMP_DMA_INT_OVRFL | \
+                                       ZYNQMP_DMA_DST_DSCR_DONE)
+
+/* Max number of descriptors per channel */
+#define ZYNQMP_DMA_NUM_DESCS   32
+
+/* Max transfer size per descriptor */
+#define ZYNQMP_DMA_MAX_TRANS_LEN       0x40000000
+
+/* Reset values for data attributes */
+#define ZYNQMP_DMA_AXCACHE_VAL         0xF
+#define ZYNQMP_DMA_ARLEN_RST_VAL       0xF
+#define ZYNQMP_DMA_AWLEN_RST_VAL       0xF
+
+#define ZYNQMP_DMA_SRC_ISSUE_RST_VAL   0x1F
+
+#define ZYNQMP_DMA_IDS_DEFAULT_MASK    0xFFF
+
+/* Bus width in bits */
+#define ZYNQMP_DMA_BUS_WIDTH_64                64
+#define ZYNQMP_DMA_BUS_WIDTH_128       128
+
+#define ZYNQMP_DMA_DESC_SIZE(chan)     (chan->desc_size)
+
+#define to_chan(chan)          container_of(chan, struct zynqmp_dma_chan, \
+                                            common)
+#define tx_to_desc(tx)         container_of(tx, struct zynqmp_dma_desc_sw, \
+                                            async_tx)
+
+/**
+ * struct zynqmp_dma_desc_ll - Hw linked list descriptor
+ * @addr: Buffer address
+ * @size: Size of the buffer
+ * @ctrl: Control word
+ * @nxtdscraddr: Next descriptor base address
+ * @rsvd: Reserved field and for Hw internal use.
+ */
+struct zynqmp_dma_desc_ll {
+       u64 addr;
+       u32 size;
+       u32 ctrl;
+       u64 nxtdscraddr;
+       u64 rsvd;
+}; __aligned(64)
+
+/**
+ * struct zynqmp_dma_desc_sw - Per Transaction structure
+ * @src: Source address for simple mode dma
+ * @dst: Destination address for simple mode dma
+ * @len: Transfer length for simple mode dma
+ * @node: Node in the channel descriptor list
+ * @tx_list: List head for the current transfer
+ * @async_tx: Async transaction descriptor
+ * @src_v: Virtual address of the src descriptor
+ * @src_p: Physical address of the src descriptor
+ * @dst_v: Virtual address of the dst descriptor
+ * @dst_p: Physical address of the dst descriptor
+ */
+struct zynqmp_dma_desc_sw {
+       u64 src;
+       u64 dst;
+       u32 len;
+       struct list_head node;
+       struct list_head tx_list;
+       struct dma_async_tx_descriptor async_tx;
+       struct zynqmp_dma_desc_ll *src_v;
+       dma_addr_t src_p;
+       struct zynqmp_dma_desc_ll *dst_v;
+       dma_addr_t dst_p;
+};
+
+/**
+ * struct zynqmp_dma_chan - Driver specific DMA channel structure
+ * @zdev: Driver specific device structure
+ * @regs: Control registers offset
+ * @lock: Descriptor operation lock
+ * @pending_list: Descriptors waiting
+ * @free_list: Descriptors free
+ * @active_list: Descriptors active
+ * @sw_desc_pool: SW descriptor pool
+ * @done_list: Complete descriptors
+ * @common: DMA common channel
+ * @desc_pool_v: Statically allocated descriptor base
+ * @desc_pool_p: Physical allocated descriptor base
+ * @desc_free_cnt: Descriptor available count
+ * @dev: The dma device
+ * @irq: Channel IRQ
+ * @is_dmacoherent: Tells whether dma operations are coherent or not
+ * @tasklet: Cleanup work after irq
+ * @idle : Channel status;
+ * @desc_size: Size of the low level descriptor
+ * @err: Channel has errors
+ * @bus_width: Bus width
+ * @src_burst_len: Source burst length
+ * @dst_burst_len: Dest burst length
+ * @clk_main: Pointer to main clock
+ * @clk_apb: Pointer to apb clock
+ */
+struct zynqmp_dma_chan {
+       struct zynqmp_dma_device *zdev;
+       void __iomem *regs;
+       spinlock_t lock;
+       struct list_head pending_list;
+       struct list_head free_list;
+       struct list_head active_list;
+       struct zynqmp_dma_desc_sw *sw_desc_pool;
+       struct list_head done_list;
+       struct dma_chan common;
+       void *desc_pool_v;
+       dma_addr_t desc_pool_p;
+       u32 desc_free_cnt;
+       struct device *dev;
+       int irq;
+       bool is_dmacoherent;
+       struct tasklet_struct tasklet;
+       bool idle;
+       u32 desc_size;
+       bool err;
+       u32 bus_width;
+       u32 src_burst_len;
+       u32 dst_burst_len;
+       struct clk *clk_main;
+       struct clk *clk_apb;
+};
+
+/**
+ * struct zynqmp_dma_device - DMA device structure
+ * @dev: Device Structure
+ * @common: DMA device structure
+ * @chan: Driver specific DMA channel
+ */
+struct zynqmp_dma_device {
+       struct device *dev;
+       struct dma_device common;
+       struct zynqmp_dma_chan *chan;
+};
+
+static inline void zynqmp_dma_writeq(struct zynqmp_dma_chan *chan, u32 reg,
+                                    u64 value)
+{
+       lo_hi_writeq(value, chan->regs + reg);
+}
+
+/**
+ * zynqmp_dma_update_desc_to_ctrlr - Updates descriptor to the controller
+ * @chan: ZynqMP DMA DMA channel pointer
+ * @desc: Transaction descriptor pointer
+ */
+static void zynqmp_dma_update_desc_to_ctrlr(struct zynqmp_dma_chan *chan,
+                                     struct zynqmp_dma_desc_sw *desc)
+{
+       dma_addr_t addr;
+
+       addr = desc->src_p;
+       zynqmp_dma_writeq(chan, ZYNQMP_DMA_SRC_START_LSB, addr);
+       addr = desc->dst_p;
+       zynqmp_dma_writeq(chan, ZYNQMP_DMA_DST_START_LSB, addr);
+}
+
+/**
+ * zynqmp_dma_desc_config_eod - Mark the descriptor as end descriptor
+ * @chan: ZynqMP DMA channel pointer
+ * @desc: Hw descriptor pointer
+ */
+static void zynqmp_dma_desc_config_eod(struct zynqmp_dma_chan *chan,
+                                      void *desc)
+{
+       struct zynqmp_dma_desc_ll *hw = (struct zynqmp_dma_desc_ll *)desc;
+
+       hw->ctrl |= ZYNQMP_DMA_DESC_CTRL_STOP;
+       hw++;
+       hw->ctrl |= ZYNQMP_DMA_DESC_CTRL_COMP_INT | ZYNQMP_DMA_DESC_CTRL_STOP;
+}
+
+/**
+ * zynqmp_dma_config_sg_ll_desc - Configure the linked list descriptor
+ * @chan: ZynqMP DMA channel pointer
+ * @sdesc: Hw descriptor pointer
+ * @src: Source buffer address
+ * @dst: Destination buffer address
+ * @len: Transfer length
+ * @prev: Previous hw descriptor pointer
+ */
+static void zynqmp_dma_config_sg_ll_desc(struct zynqmp_dma_chan *chan,
+                                  struct zynqmp_dma_desc_ll *sdesc,
+                                  dma_addr_t src, dma_addr_t dst, size_t len,
+                                  struct zynqmp_dma_desc_ll *prev)
+{
+       struct zynqmp_dma_desc_ll *ddesc = sdesc + 1;
+
+       sdesc->size = ddesc->size = len;
+       sdesc->addr = src;
+       ddesc->addr = dst;
+
+       sdesc->ctrl = ddesc->ctrl = ZYNQMP_DMA_DESC_CTRL_SIZE_256;
+       if (chan->is_dmacoherent) {
+               sdesc->ctrl |= ZYNQMP_DMA_DESC_CTRL_COHRNT;
+               ddesc->ctrl |= ZYNQMP_DMA_DESC_CTRL_COHRNT;
+       }
+
+       if (prev) {
+               dma_addr_t addr = chan->desc_pool_p +
+                           ((uintptr_t)sdesc - (uintptr_t)chan->desc_pool_v);
+               ddesc = prev + 1;
+               prev->nxtdscraddr = addr;
+               ddesc->nxtdscraddr = addr + ZYNQMP_DMA_DESC_SIZE(chan);
+       }
+}
+
+/**
+ * zynqmp_dma_init - Initialize the channel
+ * @chan: ZynqMP DMA channel pointer
+ */
+static void zynqmp_dma_init(struct zynqmp_dma_chan *chan)
+{
+       u32 val;
+
+       writel(ZYNQMP_DMA_IDS_DEFAULT_MASK, chan->regs + ZYNQMP_DMA_IDS);
+       val = readl(chan->regs + ZYNQMP_DMA_ISR);
+       writel(val, chan->regs + ZYNQMP_DMA_ISR);
+
+       if (chan->is_dmacoherent) {
+               val = ZYNQMP_DMA_AXCOHRNT;
+               val = (val & ~ZYNQMP_DMA_AXCACHE) |
+                       (ZYNQMP_DMA_AXCACHE_VAL << ZYNQMP_DMA_AXCACHE_OFST);
+               writel(val, chan->regs + ZYNQMP_DMA_DSCR_ATTR);
+       }
+
+       val = readl(chan->regs + ZYNQMP_DMA_DATA_ATTR);
+       if (chan->is_dmacoherent) {
+               val = (val & ~ZYNQMP_DMA_ARCACHE) |
+                       (ZYNQMP_DMA_AXCACHE_VAL << ZYNQMP_DMA_ARCACHE_OFST);
+               val = (val & ~ZYNQMP_DMA_AWCACHE) |
+                       (ZYNQMP_DMA_AXCACHE_VAL << ZYNQMP_DMA_AWCACHE_OFST);
+       }
+       writel(val, chan->regs + ZYNQMP_DMA_DATA_ATTR);
+
+       /* Clearing the interrupt account rgisters */
+       val = readl(chan->regs + ZYNQMP_DMA_IRQ_SRC_ACCT);
+       val = readl(chan->regs + ZYNQMP_DMA_IRQ_DST_ACCT);
+
+       chan->idle = true;
+}
+
+/**
+ * zynqmp_dma_tx_submit - Submit DMA transaction
+ * @tx: Async transaction descriptor pointer
+ *
+ * Return: cookie value
+ */
+static dma_cookie_t zynqmp_dma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+       struct zynqmp_dma_chan *chan = to_chan(tx->chan);
+       struct zynqmp_dma_desc_sw *desc, *new;
+       dma_cookie_t cookie;
+
+       new = tx_to_desc(tx);
+       spin_lock_bh(&chan->lock);
+       cookie = dma_cookie_assign(tx);
+
+       if (!list_empty(&chan->pending_list)) {
+               desc = list_last_entry(&chan->pending_list,
+                                    struct zynqmp_dma_desc_sw, node);
+               if (!list_empty(&desc->tx_list))
+                       desc = list_last_entry(&desc->tx_list,
+                                              struct zynqmp_dma_desc_sw, node);
+               desc->src_v->nxtdscraddr = new->src_p;
+               desc->src_v->ctrl &= ~ZYNQMP_DMA_DESC_CTRL_STOP;
+               desc->dst_v->nxtdscraddr = new->dst_p;
+               desc->dst_v->ctrl &= ~ZYNQMP_DMA_DESC_CTRL_STOP;
+       }
+
+       list_add_tail(&new->node, &chan->pending_list);
+       spin_unlock_bh(&chan->lock);
+
+       return cookie;
+}
+
+/**
+ * zynqmp_dma_get_descriptor - Get the sw descriptor from the pool
+ * @chan: ZynqMP DMA channel pointer
+ *
+ * Return: The sw descriptor
+ */
+static struct zynqmp_dma_desc_sw *
+zynqmp_dma_get_descriptor(struct zynqmp_dma_chan *chan)
+{
+       struct zynqmp_dma_desc_sw *desc;
+
+       spin_lock_bh(&chan->lock);
+       desc = list_first_entry(&chan->free_list,
+                               struct zynqmp_dma_desc_sw, node);
+       list_del(&desc->node);
+       spin_unlock_bh(&chan->lock);
+
+       INIT_LIST_HEAD(&desc->tx_list);
+       /* Clear the src and dst descriptor memory */
+       memset((void *)desc->src_v, 0, ZYNQMP_DMA_DESC_SIZE(chan));
+       memset((void *)desc->dst_v, 0, ZYNQMP_DMA_DESC_SIZE(chan));
+
+       return desc;
+}
+
+/**
+ * zynqmp_dma_free_descriptor - Issue pending transactions
+ * @chan: ZynqMP DMA channel pointer
+ * @sdesc: Transaction descriptor pointer
+ */
+static void zynqmp_dma_free_descriptor(struct zynqmp_dma_chan *chan,
+                                struct zynqmp_dma_desc_sw *sdesc)
+{
+       struct zynqmp_dma_desc_sw *child, *next;
+
+       chan->desc_free_cnt++;
+       list_add_tail(&sdesc->node, &chan->free_list);
+       list_for_each_entry_safe(child, next, &sdesc->tx_list, node) {
+               chan->desc_free_cnt++;
+               list_move_tail(&child->node, &chan->free_list);
+       }
+}
+
+/**
+ * zynqmp_dma_free_desc_list - Free descriptors list
+ * @chan: ZynqMP DMA channel pointer
+ * @list: List to parse and delete the descriptor
+ */
+static void zynqmp_dma_free_desc_list(struct zynqmp_dma_chan *chan,
+                                     struct list_head *list)
+{
+       struct zynqmp_dma_desc_sw *desc, *next;
+
+       list_for_each_entry_safe(desc, next, list, node)
+               zynqmp_dma_free_descriptor(chan, desc);
+}
+
+/**
+ * zynqmp_dma_alloc_chan_resources - Allocate channel resources
+ * @dchan: DMA channel
+ *
+ * Return: Number of descriptors on success and failure value on error
+ */
+static int zynqmp_dma_alloc_chan_resources(struct dma_chan *dchan)
+{
+       struct zynqmp_dma_chan *chan = to_chan(dchan);
+       struct zynqmp_dma_desc_sw *desc;
+       int i;
+
+       chan->sw_desc_pool = kzalloc(sizeof(*desc) * ZYNQMP_DMA_NUM_DESCS,
+                                    GFP_KERNEL);
+       if (!chan->sw_desc_pool)
+               return -ENOMEM;
+
+       chan->idle = true;
+       chan->desc_free_cnt = ZYNQMP_DMA_NUM_DESCS;
+
+       INIT_LIST_HEAD(&chan->free_list);
+
+       for (i = 0; i < ZYNQMP_DMA_NUM_DESCS; i++) {
+               desc = chan->sw_desc_pool + i;
+               dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
+               desc->async_tx.tx_submit = zynqmp_dma_tx_submit;
+               list_add_tail(&desc->node, &chan->free_list);
+       }
+
+       chan->desc_pool_v = dma_zalloc_coherent(chan->dev,
+                               (2 * chan->desc_size * ZYNQMP_DMA_NUM_DESCS),
+                               &chan->desc_pool_p, GFP_KERNEL);
+       if (!chan->desc_pool_v)
+               return -ENOMEM;
+
+       for (i = 0; i < ZYNQMP_DMA_NUM_DESCS; i++) {
+               desc = chan->sw_desc_pool + i;
+               desc->src_v = (struct zynqmp_dma_desc_ll *) (chan->desc_pool_v +
+                                       (i * ZYNQMP_DMA_DESC_SIZE(chan) * 2));
+               desc->dst_v = (struct zynqmp_dma_desc_ll *) (desc->src_v + 1);
+               desc->src_p = chan->desc_pool_p +
+                               (i * ZYNQMP_DMA_DESC_SIZE(chan) * 2);
+               desc->dst_p = desc->src_p + ZYNQMP_DMA_DESC_SIZE(chan);
+       }
+
+       return ZYNQMP_DMA_NUM_DESCS;
+}
+
+/**
+ * zynqmp_dma_start - Start DMA channel
+ * @chan: ZynqMP DMA channel pointer
+ */
+static void zynqmp_dma_start(struct zynqmp_dma_chan *chan)
+{
+       writel(ZYNQMP_DMA_INT_EN_DEFAULT_MASK, chan->regs + ZYNQMP_DMA_IER);
+       chan->idle = false;
+       writel(ZYNQMP_DMA_ENABLE, chan->regs + ZYNQMP_DMA_CTRL2);
+}
+
+/**
+ * zynqmp_dma_handle_ovfl_int - Process the overflow interrupt
+ * @chan: ZynqMP DMA channel pointer
+ * @status: Interrupt status value
+ */
+static void zynqmp_dma_handle_ovfl_int(struct zynqmp_dma_chan *chan, u32 status)
+{
+       u32 val;
+
+       if (status & ZYNQMP_DMA_IRQ_DST_ACCT_ERR)
+               val = readl(chan->regs + ZYNQMP_DMA_IRQ_DST_ACCT);
+       if (status & ZYNQMP_DMA_IRQ_SRC_ACCT_ERR)
+               val = readl(chan->regs + ZYNQMP_DMA_IRQ_SRC_ACCT);
+}
+
+static void zynqmp_dma_config(struct zynqmp_dma_chan *chan)
+{
+       u32 val;
+
+       val = readl(chan->regs + ZYNQMP_DMA_CTRL0);
+       val |= ZYNQMP_DMA_POINT_TYPE_SG;
+       writel(val, chan->regs + ZYNQMP_DMA_CTRL0);
+
+       val = readl(chan->regs + ZYNQMP_DMA_DATA_ATTR);
+       val = (val & ~ZYNQMP_DMA_ARLEN) |
+               (chan->src_burst_len << ZYNQMP_DMA_ARLEN_OFST);
+       val = (val & ~ZYNQMP_DMA_AWLEN) |
+               (chan->dst_burst_len << ZYNQMP_DMA_AWLEN_OFST);
+       writel(val, chan->regs + ZYNQMP_DMA_DATA_ATTR);
+}
+
+/**
+ * zynqmp_dma_device_config - Zynqmp dma device configuration
+ * @dchan: DMA channel
+ * @config: DMA device config
+ */
+static int zynqmp_dma_device_config(struct dma_chan *dchan,
+                                   struct dma_slave_config *config)
+{
+       struct zynqmp_dma_chan *chan = to_chan(dchan);
+
+       chan->src_burst_len = config->src_maxburst;
+       chan->dst_burst_len = config->dst_maxburst;
+
+       return 0;
+}
+
+/**
+ * zynqmp_dma_start_transfer - Initiate the new transfer
+ * @chan: ZynqMP DMA channel pointer
+ */
+static void zynqmp_dma_start_transfer(struct zynqmp_dma_chan *chan)
+{
+       struct zynqmp_dma_desc_sw *desc;
+
+       if (!chan->idle)
+               return;
+
+       zynqmp_dma_config(chan);
+
+       desc = list_first_entry_or_null(&chan->pending_list,
+                                       struct zynqmp_dma_desc_sw, node);
+       if (!desc)
+               return;
+
+       list_splice_tail_init(&chan->pending_list, &chan->active_list);
+       zynqmp_dma_update_desc_to_ctrlr(chan, desc);
+       zynqmp_dma_start(chan);
+}
+
+
+/**
+ * zynqmp_dma_chan_desc_cleanup - Cleanup the completed descriptors
+ * @chan: ZynqMP DMA channel
+ */
+static void zynqmp_dma_chan_desc_cleanup(struct zynqmp_dma_chan *chan)
+{
+       struct zynqmp_dma_desc_sw *desc, *next;
+
+       list_for_each_entry_safe(desc, next, &chan->done_list, node) {
+               dma_async_tx_callback callback;
+               void *callback_param;
+
+               list_del(&desc->node);
+
+               callback = desc->async_tx.callback;
+               callback_param = desc->async_tx.callback_param;
+               if (callback) {
+                       spin_unlock(&chan->lock);
+                       callback(callback_param);
+                       spin_lock(&chan->lock);
+               }
+
+               /* Run any dependencies, then free the descriptor */
+               zynqmp_dma_free_descriptor(chan, desc);
+       }
+}
+
+/**
+ * zynqmp_dma_complete_descriptor - Mark the active descriptor as complete
+ * @chan: ZynqMP DMA channel pointer
+ */
+static void zynqmp_dma_complete_descriptor(struct zynqmp_dma_chan *chan)
+{
+       struct zynqmp_dma_desc_sw *desc;
+
+       desc = list_first_entry_or_null(&chan->active_list,
+                                       struct zynqmp_dma_desc_sw, node);
+       if (!desc)
+               return;
+       list_del(&desc->node);
+       dma_cookie_complete(&desc->async_tx);
+       list_add_tail(&desc->node, &chan->done_list);
+}
+
+/**
+ * zynqmp_dma_issue_pending - Issue pending transactions
+ * @dchan: DMA channel pointer
+ */
+static void zynqmp_dma_issue_pending(struct dma_chan *dchan)
+{
+       struct zynqmp_dma_chan *chan = to_chan(dchan);
+
+       spin_lock_bh(&chan->lock);
+       zynqmp_dma_start_transfer(chan);
+       spin_unlock_bh(&chan->lock);
+}
+
+/**
+ * zynqmp_dma_free_descriptors - Free channel descriptors
+ * @dchan: DMA channel pointer
+ */
+static void zynqmp_dma_free_descriptors(struct zynqmp_dma_chan *chan)
+{
+       zynqmp_dma_free_desc_list(chan, &chan->active_list);
+       zynqmp_dma_free_desc_list(chan, &chan->pending_list);
+       zynqmp_dma_free_desc_list(chan, &chan->done_list);
+}
+
+/**
+ * zynqmp_dma_free_chan_resources - Free channel resources
+ * @dchan: DMA channel pointer
+ */
+static void zynqmp_dma_free_chan_resources(struct dma_chan *dchan)
+{
+       struct zynqmp_dma_chan *chan = to_chan(dchan);
+
+       spin_lock_bh(&chan->lock);
+       zynqmp_dma_free_descriptors(chan);
+       spin_unlock_bh(&chan->lock);
+       dma_free_coherent(chan->dev,
+               (2 * ZYNQMP_DMA_DESC_SIZE(chan) * ZYNQMP_DMA_NUM_DESCS),
+               chan->desc_pool_v, chan->desc_pool_p);
+       kfree(chan->sw_desc_pool);
+}
+
+/**
+ * zynqmp_dma_reset - Reset the channel
+ * @chan: ZynqMP DMA channel pointer
+ */
+static void zynqmp_dma_reset(struct zynqmp_dma_chan *chan)
+{
+       writel(ZYNQMP_DMA_IDS_DEFAULT_MASK, chan->regs + ZYNQMP_DMA_IDS);
+
+       zynqmp_dma_complete_descriptor(chan);
+       zynqmp_dma_chan_desc_cleanup(chan);
+       zynqmp_dma_free_descriptors(chan);
+       zynqmp_dma_init(chan);
+}
+
+/**
+ * zynqmp_dma_irq_handler - ZynqMP DMA Interrupt handler
+ * @irq: IRQ number
+ * @data: Pointer to the ZynqMP DMA channel structure
+ *
+ * Return: IRQ_HANDLED/IRQ_NONE
+ */
+static irqreturn_t zynqmp_dma_irq_handler(int irq, void *data)
+{
+       struct zynqmp_dma_chan *chan = (struct zynqmp_dma_chan *)data;
+       u32 isr, imr, status;
+       irqreturn_t ret = IRQ_NONE;
+
+       isr = readl(chan->regs + ZYNQMP_DMA_ISR);
+       imr = readl(chan->regs + ZYNQMP_DMA_IMR);
+       status = isr & ~imr;
+
+       writel(isr, chan->regs + ZYNQMP_DMA_ISR);
+       if (status & ZYNQMP_DMA_INT_DONE) {
+               tasklet_schedule(&chan->tasklet);
+               ret = IRQ_HANDLED;
+       }
+
+       if (status & ZYNQMP_DMA_DONE)
+               chan->idle = true;
+
+       if (status & ZYNQMP_DMA_INT_ERR) {
+               chan->err = true;
+               tasklet_schedule(&chan->tasklet);
+               dev_err(chan->dev, "Channel %p has errors\n", chan);
+               ret = IRQ_HANDLED;
+       }
+
+       if (status & ZYNQMP_DMA_INT_OVRFL) {
+               zynqmp_dma_handle_ovfl_int(chan, status);
+               dev_info(chan->dev, "Channel %p overflow interrupt\n", chan);
+               ret = IRQ_HANDLED;
+       }
+
+       return ret;
+}
+
+/**
+ * zynqmp_dma_do_tasklet - Schedule completion tasklet
+ * @data: Pointer to the ZynqMP DMA channel structure
+ */
+static void zynqmp_dma_do_tasklet(unsigned long data)
+{
+       struct zynqmp_dma_chan *chan = (struct zynqmp_dma_chan *)data;
+       u32 count;
+
+       spin_lock(&chan->lock);
+
+       if (chan->err) {
+               zynqmp_dma_reset(chan);
+               chan->err = false;
+               goto unlock;
+       }
+
+       count = readl(chan->regs + ZYNQMP_DMA_IRQ_DST_ACCT);
+
+       while (count) {
+               zynqmp_dma_complete_descriptor(chan);
+               zynqmp_dma_chan_desc_cleanup(chan);
+               count--;
+       }
+
+       if (chan->idle)
+               zynqmp_dma_start_transfer(chan);
+
+unlock:
+       spin_unlock(&chan->lock);
+}
+
+/**
+ * zynqmp_dma_device_terminate_all - Aborts all transfers on a channel
+ * @dchan: DMA channel pointer
+ *
+ * Return: Always '0'
+ */
+static int zynqmp_dma_device_terminate_all(struct dma_chan *dchan)
+{
+       struct zynqmp_dma_chan *chan = to_chan(dchan);
+
+       spin_lock_bh(&chan->lock);
+       writel(ZYNQMP_DMA_IDS_DEFAULT_MASK, chan->regs + ZYNQMP_DMA_IDS);
+       zynqmp_dma_free_descriptors(chan);
+       spin_unlock_bh(&chan->lock);
+
+       return 0;
+}
+
+/**
+ * zynqmp_dma_prep_memcpy - prepare descriptors for memcpy transaction
+ * @dchan: DMA channel
+ * @dma_dst: Destination buffer address
+ * @dma_src: Source buffer address
+ * @len: Transfer length
+ * @flags: transfer ack flags
+ *
+ * Return: Async transaction descriptor on success and NULL on failure
+ */
+static struct dma_async_tx_descriptor *zynqmp_dma_prep_memcpy(
+                               struct dma_chan *dchan, dma_addr_t dma_dst,
+                               dma_addr_t dma_src, size_t len, ulong flags)
+{
+       struct zynqmp_dma_chan *chan;
+       struct zynqmp_dma_desc_sw *new, *first = NULL;
+       void *desc = NULL, *prev = NULL;
+       size_t copy;
+       u32 desc_cnt;
+
+       chan = to_chan(dchan);
+
+       if (len > ZYNQMP_DMA_MAX_TRANS_LEN)
+               return NULL;
+
+       desc_cnt = DIV_ROUND_UP(len, ZYNQMP_DMA_MAX_TRANS_LEN);
+
+       spin_lock_bh(&chan->lock);
+       if (desc_cnt > chan->desc_free_cnt) {
+               spin_unlock_bh(&chan->lock);
+               dev_dbg(chan->dev, "chan %p descs are not available\n", chan);
+               return NULL;
+       }
+       chan->desc_free_cnt = chan->desc_free_cnt - desc_cnt;
+       spin_unlock_bh(&chan->lock);
+
+       do {
+               /* Allocate and populate the descriptor */
+               new = zynqmp_dma_get_descriptor(chan);
+
+               copy = min_t(size_t, len, ZYNQMP_DMA_MAX_TRANS_LEN);
+               desc = (struct zynqmp_dma_desc_ll *)new->src_v;
+               zynqmp_dma_config_sg_ll_desc(chan, desc, dma_src,
+                                            dma_dst, copy, prev);
+               prev = desc;
+               len -= copy;
+               dma_src += copy;
+               dma_dst += copy;
+               if (!first)
+                       first = new;
+               else
+                       list_add_tail(&new->node, &first->tx_list);
+       } while (len);
+
+       zynqmp_dma_desc_config_eod(chan, desc);
+       async_tx_ack(&first->async_tx);
+       first->async_tx.flags = flags;
+       return &first->async_tx;
+}
+
+/**
+ * zynqmp_dma_prep_slave_sg - prepare descriptors for a memory sg transaction
+ * @dchan: DMA channel
+ * @dst_sg: Destination scatter list
+ * @dst_sg_len: Number of entries in destination scatter list
+ * @src_sg: Source scatter list
+ * @src_sg_len: Number of entries in source scatter list
+ * @flags: transfer ack flags
+ *
+ * Return: Async transaction descriptor on success and NULL on failure
+ */
+static struct dma_async_tx_descriptor *zynqmp_dma_prep_sg(
+                       struct dma_chan *dchan, struct scatterlist *dst_sg,
+                       unsigned int dst_sg_len, struct scatterlist *src_sg,
+                       unsigned int src_sg_len, unsigned long flags)
+{
+       struct zynqmp_dma_desc_sw *new, *first = NULL;
+       struct zynqmp_dma_chan *chan = to_chan(dchan);
+       void *desc = NULL, *prev = NULL;
+       size_t len, dst_avail, src_avail;
+       dma_addr_t dma_dst, dma_src;
+       u32 desc_cnt = 0, i;
+       struct scatterlist *sg;
+
+       for_each_sg(src_sg, sg, src_sg_len, i)
+               desc_cnt += DIV_ROUND_UP(sg_dma_len(sg),
+                                        ZYNQMP_DMA_MAX_TRANS_LEN);
+
+       spin_lock_bh(&chan->lock);
+       if (desc_cnt > chan->desc_free_cnt) {
+               spin_unlock_bh(&chan->lock);
+               dev_dbg(chan->dev, "chan %p descs are not available\n", chan);
+               return NULL;
+       }
+       chan->desc_free_cnt = chan->desc_free_cnt - desc_cnt;
+       spin_unlock_bh(&chan->lock);
+
+       dst_avail = sg_dma_len(dst_sg);
+       src_avail = sg_dma_len(src_sg);
+
+       /* Run until we are out of scatterlist entries */
+       while (true) {
+               /* Allocate and populate the descriptor */
+               new = zynqmp_dma_get_descriptor(chan);
+               desc = (struct zynqmp_dma_desc_ll *)new->src_v;
+               len = min_t(size_t, src_avail, dst_avail);
+               len = min_t(size_t, len, ZYNQMP_DMA_MAX_TRANS_LEN);
+               if (len == 0)
+                       goto fetch;
+               dma_dst = sg_dma_address(dst_sg) + sg_dma_len(dst_sg) -
+                       dst_avail;
+               dma_src = sg_dma_address(src_sg) + sg_dma_len(src_sg) -
+                       src_avail;
+
+               zynqmp_dma_config_sg_ll_desc(chan, desc, dma_src, dma_dst,
+                                            len, prev);
+               prev = desc;
+               dst_avail -= len;
+               src_avail -= len;
+
+               if (!first)
+                       first = new;
+               else
+                       list_add_tail(&new->node, &first->tx_list);
+fetch:
+               /* Fetch the next dst scatterlist entry */
+               if (dst_avail == 0) {
+                       if (dst_sg_len == 0)
+                               break;
+                       dst_sg = sg_next(dst_sg);
+                       if (dst_sg == NULL)
+                               break;
+                       dst_sg_len--;
+                       dst_avail = sg_dma_len(dst_sg);
+               }
+               /* Fetch the next src scatterlist entry */
+               if (src_avail == 0) {
+                       if (src_sg_len == 0)
+                               break;
+                       src_sg = sg_next(src_sg);
+                       if (src_sg == NULL)
+                               break;
+                       src_sg_len--;
+                       src_avail = sg_dma_len(src_sg);
+               }
+       }
+
+       zynqmp_dma_desc_config_eod(chan, desc);
+       first->async_tx.flags = flags;
+       return &first->async_tx;
+}
+
+/**
+ * zynqmp_dma_chan_remove - Channel remove function
+ * @chan: ZynqMP DMA channel pointer
+ */
+static void zynqmp_dma_chan_remove(struct zynqmp_dma_chan *chan)
+{
+       if (!chan)
+               return;
+
+       devm_free_irq(chan->zdev->dev, chan->irq, chan);
+       tasklet_kill(&chan->tasklet);
+       list_del(&chan->common.device_node);
+       clk_disable_unprepare(chan->clk_apb);
+       clk_disable_unprepare(chan->clk_main);
+}
+
+/**
+ * zynqmp_dma_chan_probe - Per Channel Probing
+ * @zdev: Driver specific device structure
+ * @pdev: Pointer to the platform_device structure
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int zynqmp_dma_chan_probe(struct zynqmp_dma_device *zdev,
+                          struct platform_device *pdev)
+{
+       struct zynqmp_dma_chan *chan;
+       struct resource *res;
+       struct device_node *node = pdev->dev.of_node;
+       int err;
+
+       chan = devm_kzalloc(zdev->dev, sizeof(*chan), GFP_KERNEL);
+       if (!chan)
+               return -ENOMEM;
+       chan->dev = zdev->dev;
+       chan->zdev = zdev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       chan->regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(chan->regs))
+               return PTR_ERR(chan->regs);
+
+       chan->bus_width = ZYNQMP_DMA_BUS_WIDTH_64;
+       chan->dst_burst_len = ZYNQMP_DMA_AWLEN_RST_VAL;
+       chan->src_burst_len = ZYNQMP_DMA_ARLEN_RST_VAL;
+       err = of_property_read_u32(node, "xlnx,bus-width", &chan->bus_width);
+       if (err < 0) {
+               dev_err(&pdev->dev, "missing xlnx,bus-width property\n");
+               return err;
+       }
+
+       if (chan->bus_width != ZYNQMP_DMA_BUS_WIDTH_64 &&
+           chan->bus_width != ZYNQMP_DMA_BUS_WIDTH_128) {
+               dev_err(zdev->dev, "invalid bus-width value");
+               return -EINVAL;
+       }
+
+       chan->is_dmacoherent =  of_property_read_bool(node, "dma-coherent");
+       zdev->chan = chan;
+       tasklet_init(&chan->tasklet, zynqmp_dma_do_tasklet, (ulong)chan);
+       spin_lock_init(&chan->lock);
+       INIT_LIST_HEAD(&chan->active_list);
+       INIT_LIST_HEAD(&chan->pending_list);
+       INIT_LIST_HEAD(&chan->done_list);
+       INIT_LIST_HEAD(&chan->free_list);
+
+       dma_cookie_init(&chan->common);
+       chan->common.device = &zdev->common;
+       list_add_tail(&chan->common.device_node, &zdev->common.channels);
+
+       zynqmp_dma_init(chan);
+       chan->irq = platform_get_irq(pdev, 0);
+       if (chan->irq < 0)
+               return -ENXIO;
+       err = devm_request_irq(&pdev->dev, chan->irq, zynqmp_dma_irq_handler, 0,
+                              "zynqmp-dma", chan);
+       if (err)
+               return err;
+       chan->clk_main = devm_clk_get(&pdev->dev, "clk_main");
+       if (IS_ERR(chan->clk_main)) {
+               dev_err(&pdev->dev, "main clock not found.\n");
+               return PTR_ERR(chan->clk_main);
+       }
+
+       chan->clk_apb = devm_clk_get(&pdev->dev, "clk_apb");
+       if (IS_ERR(chan->clk_apb)) {
+               dev_err(&pdev->dev, "apb clock not found.\n");
+               return PTR_ERR(chan->clk_apb);
+       }
+
+       err = clk_prepare_enable(chan->clk_main);
+       if (err) {
+               dev_err(&pdev->dev, "Unable to enable main clock.\n");
+               return err;
+       }
+
+       err = clk_prepare_enable(chan->clk_apb);
+       if (err) {
+               clk_disable_unprepare(chan->clk_main);
+               dev_err(&pdev->dev, "Unable to enable apb clock.\n");
+               return err;
+       }
+
+       chan->desc_size = sizeof(struct zynqmp_dma_desc_ll);
+       chan->idle = true;
+       return 0;
+}
+
+/**
+ * of_zynqmp_dma_xlate - Translation function
+ * @dma_spec: Pointer to DMA specifier as found in the device tree
+ * @ofdma: Pointer to DMA controller data
+ *
+ * Return: DMA channel pointer on success and NULL on error
+ */
+static struct dma_chan *of_zynqmp_dma_xlate(struct of_phandle_args *dma_spec,
+                                           struct of_dma *ofdma)
+{
+       struct zynqmp_dma_device *zdev = ofdma->of_dma_data;
+
+       return dma_get_slave_channel(&zdev->chan->common);
+}
+
+/**
+ * zynqmp_dma_probe - Driver probe function
+ * @pdev: Pointer to the platform_device structure
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int zynqmp_dma_probe(struct platform_device *pdev)
+{
+       struct zynqmp_dma_device *zdev;
+       struct dma_device *p;
+       int ret;
+
+       zdev = devm_kzalloc(&pdev->dev, sizeof(*zdev), GFP_KERNEL);
+       if (!zdev)
+               return -ENOMEM;
+
+       zdev->dev = &pdev->dev;
+       INIT_LIST_HEAD(&zdev->common.channels);
+
+       dma_set_mask(&pdev->dev, DMA_BIT_MASK(44));
+       dma_cap_set(DMA_SG, zdev->common.cap_mask);
+       dma_cap_set(DMA_MEMCPY, zdev->common.cap_mask);
+
+       p = &zdev->common;
+       p->device_prep_dma_sg = zynqmp_dma_prep_sg;
+       p->device_prep_dma_memcpy = zynqmp_dma_prep_memcpy;
+       p->device_terminate_all = zynqmp_dma_device_terminate_all;
+       p->device_issue_pending = zynqmp_dma_issue_pending;
+       p->device_alloc_chan_resources = zynqmp_dma_alloc_chan_resources;
+       p->device_free_chan_resources = zynqmp_dma_free_chan_resources;
+       p->device_tx_status = dma_cookie_status;
+       p->device_config = zynqmp_dma_device_config;
+       p->dev = &pdev->dev;
+
+       platform_set_drvdata(pdev, zdev);
+
+       ret = zynqmp_dma_chan_probe(zdev, pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "Probing channel failed\n");
+               goto free_chan_resources;
+       }
+
+       p->dst_addr_widths = BIT(zdev->chan->bus_width / 8);
+       p->src_addr_widths = BIT(zdev->chan->bus_width / 8);
+
+       dma_async_device_register(&zdev->common);
+
+       ret = of_dma_controller_register(pdev->dev.of_node,
+                                        of_zynqmp_dma_xlate, zdev);
+       if (ret) {
+               dev_err(&pdev->dev, "Unable to register DMA to DT\n");
+               dma_async_device_unregister(&zdev->common);
+               goto free_chan_resources;
+       }
+
+       dev_info(&pdev->dev, "ZynqMP DMA driver Probe success\n");
+
+       return 0;
+
+free_chan_resources:
+       zynqmp_dma_chan_remove(zdev->chan);
+       return ret;
+}
+
+/**
+ * zynqmp_dma_remove - Driver remove function
+ * @pdev: Pointer to the platform_device structure
+ *
+ * Return: Always '0'
+ */
+static int zynqmp_dma_remove(struct platform_device *pdev)
+{
+       struct zynqmp_dma_device *zdev = platform_get_drvdata(pdev);
+
+       of_dma_controller_free(pdev->dev.of_node);
+       dma_async_device_unregister(&zdev->common);
+
+       zynqmp_dma_chan_remove(zdev->chan);
+
+       return 0;
+}
+
+static const struct of_device_id zynqmp_dma_of_match[] = {
+       { .compatible = "xlnx,zynqmp-dma-1.0", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, zynqmp_dma_of_match);
+
+static struct platform_driver zynqmp_dma_driver = {
+       .driver = {
+               .name = "xilinx-zynqmp-dma",
+               .of_match_table = zynqmp_dma_of_match,
+       },
+       .probe = zynqmp_dma_probe,
+       .remove = zynqmp_dma_remove,
+};
+
+module_platform_driver(zynqmp_dma_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Xilinx, Inc.");
+MODULE_DESCRIPTION("Xilinx ZynqMP DMA driver");
index 88e7fc7..cb8f034 100644 (file)
@@ -231,7 +231,7 @@ struct armada_gem_object *armada_gem_alloc_object(struct drm_device *dev,
 
        obj->dev_addr = DMA_ERROR_CODE;
 
-       mapping = file_inode(obj->obj.filp)->i_mapping;
+       mapping = obj->obj.filp->f_mapping;
        mapping_set_gfp_mask(mapping, GFP_HIGHUSER | __GFP_RECLAIMABLE);
 
        DRM_DEBUG_DRIVER("alloc obj %p size %zu\n", obj, size);
@@ -441,7 +441,7 @@ armada_gem_prime_map_dma_buf(struct dma_buf_attachment *attach,
                if (sg_alloc_table(sgt, count, GFP_KERNEL))
                        goto free_sgt;
 
-               mapping = file_inode(dobj->obj.filp)->i_mapping;
+               mapping = dobj->obj.filp->f_mapping;
 
                for_each_sg(sgt->sgl, sg, count, i) {
                        struct page *page;
index 3215606..ad89db3 100644 (file)
@@ -511,7 +511,7 @@ struct page **drm_gem_get_pages(struct drm_gem_object *obj)
        int i, npages;
 
        /* This is the shared memory object that backs the GEM resource */
-       mapping = file_inode(obj->filp)->i_mapping;
+       mapping = obj->filp->f_mapping;
 
        /* We already BUG_ON() for non-page-aligned sizes in
         * drm_gem_object_init(), so we should never hit this unless
index df9bcba..8c6f750 100644 (file)
@@ -660,7 +660,7 @@ static struct drm_gem_object *__etnaviv_gem_new(struct drm_device *dev,
                 * why this is required _and_ expected if you're
                 * going to pin these pages.
                 */
-               mapping = file_inode(obj->filp)->i_mapping;
+               mapping = obj->filp->f_mapping;
                mapping_set_gfp_mask(mapping, GFP_HIGHUSER);
        }
 
index aad2685..ed6117a 100644 (file)
@@ -151,7 +151,7 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
 static int
 i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj)
 {
-       struct address_space *mapping = file_inode(obj->base.filp)->i_mapping;
+       struct address_space *mapping = obj->base.filp->f_mapping;
        char *vaddr = obj->phys_handle->vaddr;
        struct sg_table *st;
        struct scatterlist *sg;
@@ -218,7 +218,7 @@ i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj)
                obj->dirty = 0;
 
        if (obj->dirty) {
-               struct address_space *mapping = file_inode(obj->base.filp)->i_mapping;
+               struct address_space *mapping = obj->base.filp->f_mapping;
                char *vaddr = obj->phys_handle->vaddr;
                int i;
 
@@ -2155,7 +2155,7 @@ i915_gem_object_invalidate(struct drm_i915_gem_object *obj)
        if (obj->base.filp == NULL)
                return;
 
-       mapping = file_inode(obj->base.filp)->i_mapping,
+       mapping = obj->base.filp->f_mapping,
        invalidate_mapping_pages(mapping, 0, (loff_t)-1);
 }
 
@@ -2271,7 +2271,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
         *
         * Fail silently without starting the shrinker
         */
-       mapping = file_inode(obj->base.filp)->i_mapping;
+       mapping = obj->base.filp->f_mapping;
        gfp = mapping_gfp_constraint(mapping, ~(__GFP_IO | __GFP_RECLAIM));
        gfp |= __GFP_NORETRY | __GFP_NOWARN;
        sg = st->sgl;
@@ -4522,7 +4522,7 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
                mask |= __GFP_DMA32;
        }
 
-       mapping = file_inode(obj->base.filp)->i_mapping;
+       mapping = obj->base.filp->f_mapping;
        mapping_set_gfp_mask(mapping, mask);
 
        i915_gem_object_init(obj, &i915_gem_object_ops);
index 03698b6..0dbd0f0 100644 (file)
@@ -1407,7 +1407,7 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev,
                if (ret)
                        goto err_free;
 
-               mapping = file_inode(obj->filp)->i_mapping;
+               mapping = obj->filp->f_mapping;
                mapping_set_gfp_mask(mapping, GFP_USER | __GFP_DMA32);
        }
 
index 077ae9b..97542c3 100644 (file)
@@ -298,7 +298,7 @@ int ttm_tt_swapin(struct ttm_tt *ttm)
        swap_storage = ttm->swap_storage;
        BUG_ON(swap_storage == NULL);
 
-       swap_space = file_inode(swap_storage)->i_mapping;
+       swap_space = swap_storage->f_mapping;
 
        for (i = 0; i < ttm->num_pages; ++i) {
                from_page = shmem_read_mapping_page(swap_space, i);
@@ -347,7 +347,7 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage)
        } else
                swap_storage = persistent_swap_storage;
 
-       swap_space = file_inode(swap_storage)->i_mapping;
+       swap_space = swap_storage->f_mapping;
 
        for (i = 0; i < ttm->num_pages; ++i) {
                from_page = ttm->pages[i];
index 5646ca4..78ac481 100644 (file)
@@ -388,6 +388,21 @@ config HID_LCPOWER
        ---help---
        Support for LC-Power RC1000MCE RF remote control.
 
+config HID_LED
+       tristate "Simple RGB LED support"
+       depends on HID
+       depends on LEDS_CLASS
+       ---help---
+       Support for simple RGB LED devices. Currently supported are:
+       - Riso Kagaku Webmail Notifier
+       - Dream Cheeky Webmail Notifier and Friends Alert
+       - ThingM blink(1)
+       - Delcom Visual Signal Indicator Generation 2
+       - Greynut Luxafor
+
+       To compile this driver as a module, choose M here: the
+       module will be called hid-led.
+
 config HID_LENOVO
        tristate "Lenovo / Thinkpad devices"
        depends on HID
@@ -819,11 +834,11 @@ config HID_THINGM
        tristate "ThingM blink(1) USB RGB LED"
        depends on HID
        depends on LEDS_CLASS
+       select HID_LED
        ---help---
-       Support for the ThingM blink(1) USB RGB LED. This driver registers a
-       Linux LED class instance, plus additional sysfs attributes to control
-       RGB colors, fade time and playing. The device is exposed through hidraw
-       to access other functions.
+       Support for the ThingM blink(1) USB RGB LED. This driver has been
+       merged into the generic hid led driver. Config symbol HID_THINGM
+       just selects HID_LED and will be removed soon.
 
 config HID_THRUSTMASTER
        tristate "ThrustMaster devices support"
@@ -936,6 +951,14 @@ config HID_SENSOR_CUSTOM_SENSOR
          standard sensors.
          Select this config option for custom/generic sensor support.
 
+config HID_ALPS
+       tristate "Alps HID device support"
+       depends on HID
+       ---help---
+       Support for Alps I2C HID touchpads and StickPointer.
+       Say Y here if you have a Alps touchpads over i2c-hid or usbhid
+       and want support for its special functionalities.
+
 endmenu
 
 endif # HID
index a2fb562..fc4b2aa 100644 (file)
@@ -21,6 +21,7 @@ hid-wiimote-y         := hid-wiimote-core.o hid-wiimote-modules.o
 hid-wiimote-$(CONFIG_DEBUG_FS) += hid-wiimote-debug.o
 
 obj-$(CONFIG_HID_A4TECH)       += hid-a4tech.o
+obj-$(CONFIG_HID_ALPS)         += hid-alps.o
 obj-$(CONFIG_HID_ACRUX)                += hid-axff.o
 obj-$(CONFIG_HID_APPLE)                += hid-apple.o
 obj-$(CONFIG_HID_APPLEIR)      += hid-appleir.o
@@ -90,12 +91,12 @@ obj-$(CONFIG_HID_SPEEDLINK) += hid-speedlink.o
 obj-$(CONFIG_HID_STEELSERIES)  += hid-steelseries.o
 obj-$(CONFIG_HID_SUNPLUS)      += hid-sunplus.o
 obj-$(CONFIG_HID_GREENASIA)    += hid-gaff.o
-obj-$(CONFIG_HID_THINGM)       += hid-thingm.o
 obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o
 obj-$(CONFIG_HID_TIVO)         += hid-tivo.o
 obj-$(CONFIG_HID_TOPSEED)      += hid-topseed.o
 obj-$(CONFIG_HID_TWINHAN)      += hid-twinhan.o
 obj-$(CONFIG_HID_UCLOGIC)      += hid-uclogic.o
+obj-$(CONFIG_HID_LED)          += hid-led.o
 obj-$(CONFIG_HID_XINMO)                += hid-xinmo.o
 obj-$(CONFIG_HID_ZEROPLUS)     += hid-zpff.o
 obj-$(CONFIG_HID_ZYDACRON)     += hid-zydacron.o
diff --git a/drivers/hid/hid-alps.c b/drivers/hid/hid-alps.c
new file mode 100644 (file)
index 0000000..048befd
--- /dev/null
@@ -0,0 +1,506 @@
+/*
+ *  Copyright (c) 2016 Masaki Ota <masaki.ota@jp.alps.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/hid.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/module.h>
+#include <asm/unaligned.h>
+#include "hid-ids.h"
+
+/* ALPS Device Product ID */
+#define HID_PRODUCT_ID_T3_BTNLESS      0xD0C0
+#define HID_PRODUCT_ID_COSMO           0x1202
+#define HID_PRODUCT_ID_U1_PTP_1                0x1207
+#define HID_PRODUCT_ID_U1                      0x1209
+#define HID_PRODUCT_ID_U1_PTP_2                0x120A
+#define HID_PRODUCT_ID_U1_DUAL         0x120B
+#define HID_PRODUCT_ID_T4_BTNLESS      0x120C
+
+#define DEV_SINGLEPOINT                                0x01
+#define DEV_DUALPOINT                          0x02
+
+#define U1_MOUSE_REPORT_ID                     0x01 /* Mouse data ReportID */
+#define U1_ABSOLUTE_REPORT_ID          0x03 /* Absolute data ReportID */
+#define U1_FEATURE_REPORT_ID           0x05 /* Feature ReportID */
+#define U1_SP_ABSOLUTE_REPORT_ID       0x06 /* Feature ReportID */
+
+#define U1_FEATURE_REPORT_LEN          0x08 /* Feature Report Length */
+#define U1_FEATURE_REPORT_LEN_ALL      0x0A
+#define U1_CMD_REGISTER_READ           0xD1
+#define U1_CMD_REGISTER_WRITE          0xD2
+
+#define        U1_DEVTYPE_SP_SUPPORT           0x10 /* SP Support */
+#define        U1_DISABLE_DEV                          0x01
+#define U1_TP_ABS_MODE                         0x02
+#define        U1_SP_ABS_MODE                          0x80
+
+#define ADDRESS_U1_DEV_CTRL_1  0x00800040
+#define ADDRESS_U1_DEVICE_TYP  0x00800043
+#define ADDRESS_U1_NUM_SENS_X  0x00800047
+#define ADDRESS_U1_NUM_SENS_Y  0x00800048
+#define ADDRESS_U1_PITCH_SENS_X        0x00800049
+#define ADDRESS_U1_PITCH_SENS_Y        0x0080004A
+#define ADDRESS_U1_RESO_DWN_ABS 0x0080004E
+#define ADDRESS_U1_PAD_BTN             0x00800052
+#define ADDRESS_U1_SP_BTN              0x0080009F
+
+#define MAX_TOUCHES    5
+
+/**
+ * struct u1_data
+ *
+ * @input: pointer to the kernel input device
+ * @input2: pointer to the kernel input2 device
+ * @hdev: pointer to the struct hid_device
+ *
+ * @dev_ctrl: device control parameter
+ * @dev_type: device type
+ * @sen_line_num_x: number of sensor line of X
+ * @sen_line_num_y: number of sensor line of Y
+ * @pitch_x: sensor pitch of X
+ * @pitch_y: sensor pitch of Y
+ * @resolution: resolution
+ * @btn_info: button information
+ * @x_active_len_mm: active area length of X (mm)
+ * @y_active_len_mm: active area length of Y (mm)
+ * @x_max: maximum x coordinate value
+ * @y_max: maximum y coordinate value
+ * @btn_cnt: number of buttons
+ * @sp_btn_cnt: number of stick buttons
+ */
+struct u1_dev {
+       struct input_dev *input;
+       struct input_dev *input2;
+       struct hid_device *hdev;
+
+       u8      dev_ctrl;
+       u8      dev_type;
+       u8      sen_line_num_x;
+       u8      sen_line_num_y;
+       u8      pitch_x;
+       u8      pitch_y;
+       u8      resolution;
+       u8      btn_info;
+       u8      sp_btn_info;
+       u32     x_active_len_mm;
+       u32     y_active_len_mm;
+       u32     x_max;
+       u32     y_max;
+       u32     btn_cnt;
+       u32     sp_btn_cnt;
+};
+
+static int u1_read_write_register(struct hid_device *hdev, u32 address,
+       u8 *read_val, u8 write_val, bool read_flag)
+{
+       int ret, i;
+       u8 check_sum;
+       u8 *input;
+       u8 *readbuf;
+
+       input = kzalloc(U1_FEATURE_REPORT_LEN, GFP_KERNEL);
+       if (!input)
+               return -ENOMEM;
+
+       input[0] = U1_FEATURE_REPORT_ID;
+       if (read_flag) {
+               input[1] = U1_CMD_REGISTER_READ;
+               input[6] = 0x00;
+       } else {
+               input[1] = U1_CMD_REGISTER_WRITE;
+               input[6] = write_val;
+       }
+
+       put_unaligned_le32(address, input + 2);
+
+       /* Calculate the checksum */
+       check_sum = U1_FEATURE_REPORT_LEN_ALL;
+       for (i = 0; i < U1_FEATURE_REPORT_LEN - 1; i++)
+               check_sum += input[i];
+
+       input[7] = check_sum;
+       ret = hid_hw_raw_request(hdev, U1_FEATURE_REPORT_ID, input,
+                       U1_FEATURE_REPORT_LEN,
+                       HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed to read command (%d)\n", ret);
+               goto exit;
+       }
+
+       if (read_flag) {
+               readbuf = kzalloc(U1_FEATURE_REPORT_LEN, GFP_KERNEL);
+               if (!readbuf) {
+                       kfree(input);
+                       return -ENOMEM;
+               }
+
+               ret = hid_hw_raw_request(hdev, U1_FEATURE_REPORT_ID, readbuf,
+                               U1_FEATURE_REPORT_LEN,
+                               HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
+
+               if (ret < 0) {
+                       dev_err(&hdev->dev, "failed read register (%d)\n", ret);
+                       goto exit;
+               }
+
+               *read_val = readbuf[6];
+
+               kfree(readbuf);
+       }
+
+       ret = 0;
+
+exit:
+       kfree(input);
+       return ret;
+}
+
+static int alps_raw_event(struct hid_device *hdev,
+               struct hid_report *report, u8 *data, int size)
+{
+       unsigned int x, y, z;
+       int i;
+       short sp_x, sp_y;
+       struct u1_dev *hdata = hid_get_drvdata(hdev);
+
+       switch (data[0]) {
+       case U1_MOUSE_REPORT_ID:
+               break;
+       case U1_FEATURE_REPORT_ID:
+               break;
+       case U1_ABSOLUTE_REPORT_ID:
+               for (i = 0; i < MAX_TOUCHES; i++) {
+                       u8 *contact = &data[i * 5];
+
+                       x = get_unaligned_le16(contact + 3);
+                       y = get_unaligned_le16(contact + 5);
+                       z = contact[7] & 0x7F;
+
+                       input_mt_slot(hdata->input, i);
+
+                       if (z != 0) {
+                               input_mt_report_slot_state(hdata->input,
+                                       MT_TOOL_FINGER, 1);
+                       } else {
+                               input_mt_report_slot_state(hdata->input,
+                                       MT_TOOL_FINGER, 0);
+                               break;
+                       }
+
+                       input_report_abs(hdata->input, ABS_MT_POSITION_X, x);
+                       input_report_abs(hdata->input, ABS_MT_POSITION_Y, y);
+                       input_report_abs(hdata->input, ABS_MT_PRESSURE, z);
+
+               }
+
+               input_mt_sync_frame(hdata->input);
+
+               input_report_key(hdata->input, BTN_LEFT,
+                       data[1] & 0x1);
+               input_report_key(hdata->input, BTN_RIGHT,
+                       (data[1] & 0x2));
+               input_report_key(hdata->input, BTN_MIDDLE,
+                       (data[1] & 0x4));
+
+               input_sync(hdata->input);
+
+               return 1;
+
+       case U1_SP_ABSOLUTE_REPORT_ID:
+               sp_x = get_unaligned_le16(data+2);
+               sp_y = get_unaligned_le16(data+4);
+
+               sp_x = sp_x / 8;
+               sp_y = sp_y / 8;
+
+               input_report_rel(hdata->input2, REL_X, sp_x);
+               input_report_rel(hdata->input2, REL_Y, sp_y);
+
+               input_report_key(hdata->input2, BTN_LEFT,
+                       data[1] & 0x1);
+               input_report_key(hdata->input2, BTN_RIGHT,
+                       (data[1] & 0x2));
+               input_report_key(hdata->input2, BTN_MIDDLE,
+                       (data[1] & 0x4));
+
+               input_sync(hdata->input2);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int alps_post_reset(struct hid_device *hdev)
+{
+       return u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
+                               NULL, U1_TP_ABS_MODE, false);
+}
+
+static int alps_post_resume(struct hid_device *hdev)
+{
+       return u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
+                               NULL, U1_TP_ABS_MODE, false);
+}
+#endif /* CONFIG_PM */
+
+static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi)
+{
+       struct u1_dev *data = hid_get_drvdata(hdev);
+       struct input_dev *input = hi->input, *input2;
+       struct u1_dev devInfo;
+       int ret;
+       int res_x, res_y, i;
+
+       data->input = input;
+
+       hid_dbg(hdev, "Opening low level driver\n");
+       ret = hid_hw_open(hdev);
+       if (ret)
+               return ret;
+
+       /* Allow incoming hid reports */
+       hid_device_io_start(hdev);
+
+       /* Device initialization */
+       ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
+                       &devInfo.dev_ctrl, 0, true);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed U1_DEV_CTRL_1 (%d)\n", ret);
+               goto exit;
+       }
+
+       devInfo.dev_ctrl &= ~U1_DISABLE_DEV;
+       devInfo.dev_ctrl |= U1_TP_ABS_MODE;
+       ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
+                       NULL, devInfo.dev_ctrl, false);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed to change TP mode (%d)\n", ret);
+               goto exit;
+       }
+
+       ret = u1_read_write_register(hdev, ADDRESS_U1_NUM_SENS_X,
+                       &devInfo.sen_line_num_x, 0, true);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed U1_NUM_SENS_X (%d)\n", ret);
+               goto exit;
+       }
+
+       ret = u1_read_write_register(hdev, ADDRESS_U1_NUM_SENS_Y,
+                       &devInfo.sen_line_num_y, 0, true);
+               if (ret < 0) {
+               dev_err(&hdev->dev, "failed U1_NUM_SENS_Y (%d)\n", ret);
+               goto exit;
+       }
+
+       ret = u1_read_write_register(hdev, ADDRESS_U1_PITCH_SENS_X,
+                       &devInfo.pitch_x, 0, true);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed U1_PITCH_SENS_X (%d)\n", ret);
+               goto exit;
+       }
+
+       ret = u1_read_write_register(hdev, ADDRESS_U1_PITCH_SENS_Y,
+                       &devInfo.pitch_y, 0, true);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed U1_PITCH_SENS_Y (%d)\n", ret);
+               goto exit;
+       }
+
+       ret = u1_read_write_register(hdev, ADDRESS_U1_RESO_DWN_ABS,
+               &devInfo.resolution, 0, true);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed U1_RESO_DWN_ABS (%d)\n", ret);
+               goto exit;
+       }
+
+       ret = u1_read_write_register(hdev, ADDRESS_U1_PAD_BTN,
+                       &devInfo.btn_info, 0, true);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed U1_PAD_BTN (%d)\n", ret);
+               goto exit;
+       }
+
+       /* Check StickPointer device */
+       ret = u1_read_write_register(hdev, ADDRESS_U1_DEVICE_TYP,
+                       &devInfo.dev_type, 0, true);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed U1_DEVICE_TYP (%d)\n", ret);
+               goto exit;
+       }
+
+       devInfo.x_active_len_mm =
+               (devInfo.pitch_x * (devInfo.sen_line_num_x - 1)) / 10;
+       devInfo.y_active_len_mm =
+               (devInfo.pitch_y * (devInfo.sen_line_num_y - 1)) / 10;
+
+       devInfo.x_max =
+               (devInfo.resolution << 2) * (devInfo.sen_line_num_x - 1);
+       devInfo.y_max =
+               (devInfo.resolution << 2) * (devInfo.sen_line_num_y - 1);
+
+       __set_bit(EV_ABS, input->evbit);
+       input_set_abs_params(input, ABS_MT_POSITION_X, 1, devInfo.x_max, 0, 0);
+       input_set_abs_params(input, ABS_MT_POSITION_Y, 1, devInfo.y_max, 0, 0);
+
+       if (devInfo.x_active_len_mm && devInfo.y_active_len_mm) {
+               res_x = (devInfo.x_max - 1) / devInfo.x_active_len_mm;
+               res_y = (devInfo.y_max - 1) / devInfo.y_active_len_mm;
+
+               input_abs_set_res(input, ABS_MT_POSITION_X, res_x);
+               input_abs_set_res(input, ABS_MT_POSITION_Y, res_y);
+       }
+
+       input_set_abs_params(input, ABS_MT_PRESSURE, 0, 64, 0, 0);
+
+       input_mt_init_slots(input, MAX_TOUCHES, INPUT_MT_POINTER);
+
+       __set_bit(EV_KEY, input->evbit);
+       if ((devInfo.btn_info & 0x0F) == (devInfo.btn_info & 0xF0) >> 4) {
+               devInfo.btn_cnt = (devInfo.btn_info & 0x0F);
+       } else {
+               /* Button pad */
+               devInfo.btn_cnt = 1;
+               __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
+       }
+
+       for (i = 0; i < devInfo.btn_cnt; i++)
+               __set_bit(BTN_LEFT + i, input->keybit);
+
+
+       /* Stick device initialization */
+       if (devInfo.dev_type & U1_DEVTYPE_SP_SUPPORT) {
+
+               input2 = input_allocate_device();
+               if (!input2) {
+                       input_free_device(input2);
+                       goto exit;
+               }
+
+               data->input2 = input2;
+
+               devInfo.dev_ctrl |= U1_SP_ABS_MODE;
+               ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
+                       NULL, devInfo.dev_ctrl, false);
+               if (ret < 0) {
+                       dev_err(&hdev->dev, "failed SP mode (%d)\n", ret);
+                       input_free_device(input2);
+                       goto exit;
+               }
+
+               ret = u1_read_write_register(hdev, ADDRESS_U1_SP_BTN,
+                       &devInfo.sp_btn_info, 0, true);
+               if (ret < 0) {
+                       dev_err(&hdev->dev, "failed U1_SP_BTN (%d)\n", ret);
+                       input_free_device(input2);
+                       goto exit;
+               }
+
+               input2->phys = input->phys;
+               input2->name = "DualPoint Stick";
+               input2->id.bustype = BUS_I2C;
+               input2->id.vendor  = input->id.vendor;
+               input2->id.product = input->id.product;
+               input2->id.version = input->id.version;
+               input2->dev.parent = input->dev.parent;
+
+               __set_bit(EV_KEY, input2->evbit);
+               devInfo.sp_btn_cnt = (devInfo.sp_btn_info & 0x0F);
+               for (i = 0; i < devInfo.sp_btn_cnt; i++)
+                       __set_bit(BTN_LEFT + i, input2->keybit);
+
+               __set_bit(EV_REL, input2->evbit);
+               __set_bit(REL_X, input2->relbit);
+               __set_bit(REL_Y, input2->relbit);
+               __set_bit(INPUT_PROP_POINTER, input2->propbit);
+               __set_bit(INPUT_PROP_POINTING_STICK, input2->propbit);
+
+               if (input_register_device(data->input2)) {
+                       input_free_device(input2);
+                       goto exit;
+               }
+       }
+
+exit:
+       hid_device_io_stop(hdev);
+       hid_hw_close(hdev);
+       return ret;
+}
+
+static int alps_input_mapping(struct hid_device *hdev,
+               struct hid_input *hi, struct hid_field *field,
+               struct hid_usage *usage, unsigned long **bit, int *max)
+{
+       return -1;
+}
+
+static int alps_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       struct u1_dev *data = NULL;
+       int ret;
+
+       data = devm_kzalloc(&hdev->dev, sizeof(struct u1_dev), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->hdev = hdev;
+       hid_set_drvdata(hdev, data);
+
+       hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               hid_err(hdev, "parse failed\n");
+               return ret;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+       if (ret) {
+               hid_err(hdev, "hw start failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static void alps_remove(struct hid_device *hdev)
+{
+       hid_hw_stop(hdev);
+}
+
+static const struct hid_device_id alps_id[] = {
+       { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY,
+               USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, alps_id);
+
+static struct hid_driver alps_driver = {
+       .name = "hid-alps",
+       .id_table               = alps_id,
+       .probe                  = alps_probe,
+       .remove                 = alps_remove,
+       .raw_event              = alps_raw_event,
+       .input_mapping          = alps_input_mapping,
+       .input_configured       = alps_input_configured,
+#ifdef CONFIG_PM
+       .resume                 = alps_post_resume,
+       .reset_resume           = alps_post_reset,
+#endif
+};
+
+module_hid_driver(alps_driver);
+
+MODULE_AUTHOR("Masaki Ota <masaki.ota@jp.alps.com>");
+MODULE_DESCRIPTION("ALPS HID driver");
+MODULE_LICENSE("GPL");
index 884d82f..2e04608 100644 (file)
@@ -474,6 +474,8 @@ static const struct hid_device_id apple_devices[] = {
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI),
+               .driver_data = APPLE_HAS_FN },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
                .driver_data = APPLE_HAS_FN },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO),
index 8ea3a26..08f53c7 100644 (file)
@@ -1772,6 +1772,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0xf705) },
+       { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) },
@@ -1851,6 +1852,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
        { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_NOTEBOOK_KEYBOARD) },
@@ -1877,8 +1879,11 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_4) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DELCOM, USB_DEVICE_ID_DELCOM_VISUAL_IND) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_WN) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_FA) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0030) },
@@ -1962,6 +1967,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_LUXAFOR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_KEYBOARD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) },
@@ -2008,6 +2014,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, HID_ANY_ID) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_RISO_KAGAKU, USB_DEVICE_ID_RI_KA_WEBMAIL) },
 #if IS_ENABLED(CONFIG_HID_ROCCAT)
        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
@@ -2348,8 +2355,6 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_DEALEXTREAME, USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x0004) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x000a) },
        { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0400) },
        { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0401) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
@@ -2486,7 +2491,6 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DPAD) },
 #endif
        { HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_RISO_KAGAKU, USB_DEVICE_ID_RI_KA_WEBMAIL) },
        { }
 };
 
index 3eec09a..4ed9a4f 100644 (file)
@@ -70,6 +70,9 @@
 #define USB_VENDOR_ID_ALPS             0x0433
 #define USB_DEVICE_ID_IBM_GAMEPAD      0x1101
 
+#define USB_VENDOR_ID_ALPS_JP          0x044E
+#define HID_DEVICE_ID_ALPS_U1_DUAL     0x120B
+
 #define USB_VENDOR_ID_ANTON            0x1130
 #define USB_DEVICE_ID_ANTON_TOUCH_PAD  0x3101
 
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI  0x0255
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO   0x0256
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS   0x0257
+#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI   0x0267
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI   0x0290
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO    0x0291
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS    0x0292
 #define USB_VENDOR_ID_DEALEXTREAME     0x10c5
 #define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701        0x819a
 
+#define USB_VENDOR_ID_DELCOM           0x0fc5
+#define USB_DEVICE_ID_DELCOM_VISUAL_IND        0xb080
+
 #define USB_VENDOR_ID_DELORME          0x1163
 #define USB_DEVICE_ID_DELORME_EARTHMATE        0x0100
 #define USB_DEVICE_ID_DELORME_EM_LT20  0x0200
 #define USB_DEVICE_ID_ELECOM_BM084     0x0061
 
 #define USB_VENDOR_ID_DREAM_CHEEKY     0x1d34
+#define USB_DEVICE_ID_DREAM_CHEEKY_WN  0x0004
+#define USB_DEVICE_ID_DREAM_CHEEKY_FA  0x000a
 
 #define USB_VENDOR_ID_ELITEGROUP       0x03fc
 #define USB_DEVICE_ID_ELITEGROUP_05D8  0x05d8
 #define USB_DEVICE_ID_PICOLCD_BOOTLOADER       0xf002
 #define USB_DEVICE_ID_PICK16F1454      0x0042
 #define USB_DEVICE_ID_PICK16F1454_V2   0xf2f7
+#define USB_DEVICE_ID_LUXAFOR          0xf372
 
 #define USB_VENDOR_ID_MICROSOFT                0x045e
 #define USB_DEVICE_ID_SIDEWINDER_GV    0x003b
diff --git a/drivers/hid/hid-led.c b/drivers/hid/hid-led.c
new file mode 100644 (file)
index 0000000..d8d55f3
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ * Simple USB RGB LED driver
+ *
+ * Copyright 2016 Heiner Kallweit <hkallweit1@gmail.com>
+ * Based on drivers/hid/hid-thingm.c and
+ * drivers/usb/misc/usbled.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ */
+
+#include <linux/hid.h>
+#include <linux/hidraw.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+
+#include "hid-ids.h"
+
+enum hidled_report_type {
+       RAW_REQUEST,
+       OUTPUT_REPORT
+};
+
+enum hidled_type {
+       RISO_KAGAKU,
+       DREAM_CHEEKY,
+       THINGM,
+       DELCOM,
+       LUXAFOR,
+};
+
+static unsigned const char riso_kagaku_tbl[] = {
+/* R+2G+4B -> riso kagaku color index */
+       [0] = 0, /* black   */
+       [1] = 2, /* red     */
+       [2] = 1, /* green   */
+       [3] = 5, /* yellow  */
+       [4] = 3, /* blue    */
+       [5] = 6, /* magenta */
+       [6] = 4, /* cyan    */
+       [7] = 7  /* white   */
+};
+
+#define RISO_KAGAKU_IX(r, g, b) riso_kagaku_tbl[((r)?1:0)+((g)?2:0)+((b)?4:0)]
+
+union delcom_packet {
+       __u8 data[8];
+       struct {
+               __u8 major_cmd;
+               __u8 minor_cmd;
+               __u8 data_lsb;
+               __u8 data_msb;
+       } tx;
+       struct {
+               __u8 cmd;
+       } rx;
+       struct {
+               __le16 family_code;
+               __le16 security_code;
+               __u8 fw_version;
+       } fw;
+};
+
+#define DELCOM_GREEN_LED       0
+#define DELCOM_RED_LED         1
+#define DELCOM_BLUE_LED                2
+
+struct hidled_device;
+struct hidled_rgb;
+
+struct hidled_config {
+       enum hidled_type        type;
+       const char              *name;
+       const char              *short_name;
+       enum led_brightness     max_brightness;
+       int                     num_leds;
+       size_t                  report_size;
+       enum hidled_report_type report_type;
+       int (*init)(struct hidled_device *ldev);
+       int (*write)(struct led_classdev *cdev, enum led_brightness br);
+};
+
+struct hidled_led {
+       struct led_classdev     cdev;
+       struct hidled_rgb       *rgb;
+       char                    name[32];
+};
+
+struct hidled_rgb {
+       struct hidled_device    *ldev;
+       struct hidled_led       red;
+       struct hidled_led       green;
+       struct hidled_led       blue;
+       u8                      num;
+};
+
+struct hidled_device {
+       const struct hidled_config *config;
+       struct hid_device       *hdev;
+       struct hidled_rgb       *rgb;
+       struct mutex            lock;
+};
+
+#define MAX_REPORT_SIZE                16
+
+#define to_hidled_led(arg) container_of(arg, struct hidled_led, cdev)
+
+static bool riso_kagaku_switch_green_blue;
+module_param(riso_kagaku_switch_green_blue, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(riso_kagaku_switch_green_blue,
+       "switch green and blue RGB component for Riso Kagaku devices");
+
+static int hidled_send(struct hidled_device *ldev, __u8 *buf)
+{
+       int ret;
+
+       mutex_lock(&ldev->lock);
+
+       if (ldev->config->report_type == RAW_REQUEST)
+               ret = hid_hw_raw_request(ldev->hdev, buf[0], buf,
+                                        ldev->config->report_size,
+                                        HID_FEATURE_REPORT,
+                                        HID_REQ_SET_REPORT);
+       else if (ldev->config->report_type == OUTPUT_REPORT)
+               ret = hid_hw_output_report(ldev->hdev, buf,
+                                          ldev->config->report_size);
+       else
+               ret = -EINVAL;
+
+       mutex_unlock(&ldev->lock);
+
+       if (ret < 0)
+               return ret;
+
+       return ret == ldev->config->report_size ? 0 : -EMSGSIZE;
+}
+
+/* reading data is supported for report type RAW_REQUEST only */
+static int hidled_recv(struct hidled_device *ldev, __u8 *buf)
+{
+       int ret;
+
+       if (ldev->config->report_type != RAW_REQUEST)
+               return -EINVAL;
+
+       mutex_lock(&ldev->lock);
+
+       ret = hid_hw_raw_request(ldev->hdev, buf[0], buf,
+                                ldev->config->report_size,
+                                HID_FEATURE_REPORT,
+                                HID_REQ_SET_REPORT);
+       if (ret < 0)
+               goto err;
+
+       ret = hid_hw_raw_request(ldev->hdev, buf[0], buf,
+                                ldev->config->report_size,
+                                HID_FEATURE_REPORT,
+                                HID_REQ_GET_REPORT);
+err:
+       mutex_unlock(&ldev->lock);
+
+       return ret < 0 ? ret : 0;
+}
+
+static u8 riso_kagaku_index(struct hidled_rgb *rgb)
+{
+       enum led_brightness r, g, b;
+
+       r = rgb->red.cdev.brightness;
+       g = rgb->green.cdev.brightness;
+       b = rgb->blue.cdev.brightness;
+
+       if (riso_kagaku_switch_green_blue)
+               return RISO_KAGAKU_IX(r, b, g);
+       else
+               return RISO_KAGAKU_IX(r, g, b);
+}
+
+static int riso_kagaku_write(struct led_classdev *cdev, enum led_brightness br)
+{
+       struct hidled_led *led = to_hidled_led(cdev);
+       struct hidled_rgb *rgb = led->rgb;
+       __u8 buf[MAX_REPORT_SIZE] = {};
+
+       buf[1] = riso_kagaku_index(rgb);
+
+       return hidled_send(rgb->ldev, buf);
+}
+
+static int dream_cheeky_write(struct led_classdev *cdev, enum led_brightness br)
+{
+       struct hidled_led *led = to_hidled_led(cdev);
+       struct hidled_rgb *rgb = led->rgb;
+       __u8 buf[MAX_REPORT_SIZE] = {};
+
+       buf[1] = rgb->red.cdev.brightness;
+       buf[2] = rgb->green.cdev.brightness;
+       buf[3] = rgb->blue.cdev.brightness;
+       buf[7] = 0x1a;
+       buf[8] = 0x05;
+
+       return hidled_send(rgb->ldev, buf);
+}
+
+static int dream_cheeky_init(struct hidled_device *ldev)
+{
+       __u8 buf[MAX_REPORT_SIZE] = {};
+
+       /* Dream Cheeky magic */
+       buf[1] = 0x1f;
+       buf[2] = 0x02;
+       buf[4] = 0x5f;
+       buf[7] = 0x1a;
+       buf[8] = 0x03;
+
+       return hidled_send(ldev, buf);
+}
+
+static int _thingm_write(struct led_classdev *cdev, enum led_brightness br,
+                        u8 offset)
+{
+       struct hidled_led *led = to_hidled_led(cdev);
+       __u8 buf[MAX_REPORT_SIZE] = { 1, 'c' };
+
+       buf[2] = led->rgb->red.cdev.brightness;
+       buf[3] = led->rgb->green.cdev.brightness;
+       buf[4] = led->rgb->blue.cdev.brightness;
+       buf[7] = led->rgb->num + offset;
+
+       return hidled_send(led->rgb->ldev, buf);
+}
+
+static int thingm_write_v1(struct led_classdev *cdev, enum led_brightness br)
+{
+       return _thingm_write(cdev, br, 0);
+}
+
+static int thingm_write(struct led_classdev *cdev, enum led_brightness br)
+{
+       return _thingm_write(cdev, br, 1);
+}
+
+static const struct hidled_config hidled_config_thingm_v1 = {
+       .name = "ThingM blink(1) v1",
+       .short_name = "thingm",
+       .max_brightness = 255,
+       .num_leds = 1,
+       .report_size = 9,
+       .report_type = RAW_REQUEST,
+       .write = thingm_write_v1,
+};
+
+static int thingm_init(struct hidled_device *ldev)
+{
+       __u8 buf[MAX_REPORT_SIZE] = { 1, 'v' };
+       int ret;
+
+       ret = hidled_recv(ldev, buf);
+       if (ret)
+               return ret;
+
+       /* Check for firmware major version 1 */
+       if (buf[3] == '1')
+               ldev->config = &hidled_config_thingm_v1;
+
+       return 0;
+}
+
+static inline int delcom_get_lednum(const struct hidled_led *led)
+{
+       if (led == &led->rgb->red)
+               return DELCOM_RED_LED;
+       else if (led == &led->rgb->green)
+               return DELCOM_GREEN_LED;
+       else
+               return DELCOM_BLUE_LED;
+}
+
+static int delcom_enable_led(struct hidled_led *led)
+{
+       union delcom_packet dp = { .tx.major_cmd = 101, .tx.minor_cmd = 12 };
+
+       dp.tx.data_lsb = 1 << delcom_get_lednum(led);
+       dp.tx.data_msb = 0;
+
+       return hidled_send(led->rgb->ldev, dp.data);
+}
+
+static int delcom_set_pwm(struct hidled_led *led)
+{
+       union delcom_packet dp = { .tx.major_cmd = 101, .tx.minor_cmd = 34 };
+
+       dp.tx.data_lsb = delcom_get_lednum(led);
+       dp.tx.data_msb = led->cdev.brightness;
+
+       return hidled_send(led->rgb->ldev, dp.data);
+}
+
+static int delcom_write(struct led_classdev *cdev, enum led_brightness br)
+{
+       struct hidled_led *led = to_hidled_led(cdev);
+       int ret;
+
+       /*
+        * enable LED
+        * We can't do this in the init function already because the device
+        * is internally reset later.
+        */
+       ret = delcom_enable_led(led);
+       if (ret)
+               return ret;
+
+       return delcom_set_pwm(led);
+}
+
+static int delcom_init(struct hidled_device *ldev)
+{
+       union delcom_packet dp = { .rx.cmd = 104 };
+       int ret;
+
+       ret = hidled_recv(ldev, dp.data);
+       if (ret)
+               return ret;
+       /*
+        * Several Delcom devices share the same USB VID/PID
+        * Check for family id 2 for Visual Signal Indicator
+        */
+       return le16_to_cpu(dp.fw.family_code) == 2 ? 0 : -ENODEV;
+}
+
+static int luxafor_write(struct led_classdev *cdev, enum led_brightness br)
+{
+       struct hidled_led *led = to_hidled_led(cdev);
+       __u8 buf[MAX_REPORT_SIZE] = { [1] = 1 };
+
+       buf[2] = led->rgb->num + 1;
+       buf[3] = led->rgb->red.cdev.brightness;
+       buf[4] = led->rgb->green.cdev.brightness;
+       buf[5] = led->rgb->blue.cdev.brightness;
+
+       return hidled_send(led->rgb->ldev, buf);
+}
+
+static const struct hidled_config hidled_configs[] = {
+       {
+               .type = RISO_KAGAKU,
+               .name = "Riso Kagaku Webmail Notifier",
+               .short_name = "riso_kagaku",
+               .max_brightness = 1,
+               .num_leds = 1,
+               .report_size = 6,
+               .report_type = OUTPUT_REPORT,
+               .write = riso_kagaku_write,
+       },
+       {
+               .type = DREAM_CHEEKY,
+               .name = "Dream Cheeky Webmail Notifier",
+               .short_name = "dream_cheeky",
+               .max_brightness = 31,
+               .num_leds = 1,
+               .report_size = 9,
+               .report_type = RAW_REQUEST,
+               .init = dream_cheeky_init,
+               .write = dream_cheeky_write,
+       },
+       {
+               .type = THINGM,
+               .name = "ThingM blink(1)",
+               .short_name = "thingm",
+               .max_brightness = 255,
+               .num_leds = 2,
+               .report_size = 9,
+               .report_type = RAW_REQUEST,
+               .init = thingm_init,
+               .write = thingm_write,
+       },
+       {
+               .type = DELCOM,
+               .name = "Delcom Visual Signal Indicator G2",
+               .short_name = "delcom",
+               .max_brightness = 100,
+               .num_leds = 1,
+               .report_size = 8,
+               .report_type = RAW_REQUEST,
+               .init = delcom_init,
+               .write = delcom_write,
+       },
+       {
+               .type = LUXAFOR,
+               .name = "Greynut Luxafor",
+               .short_name = "luxafor",
+               .max_brightness = 255,
+               .num_leds = 6,
+               .report_size = 9,
+               .report_type = OUTPUT_REPORT,
+               .write = luxafor_write,
+       },
+};
+
+static int hidled_init_led(struct hidled_led *led, const char *color_name,
+                          struct hidled_rgb *rgb, unsigned int minor)
+{
+       const struct hidled_config *config = rgb->ldev->config;
+
+       if (config->num_leds > 1)
+               snprintf(led->name, sizeof(led->name), "%s%u:%s:led%u",
+                        config->short_name, minor, color_name, rgb->num);
+       else
+               snprintf(led->name, sizeof(led->name), "%s%u:%s",
+                        config->short_name, minor, color_name);
+       led->cdev.name = led->name;
+       led->cdev.max_brightness = config->max_brightness;
+       led->cdev.brightness_set_blocking = config->write;
+       led->cdev.flags = LED_HW_PLUGGABLE;
+       led->rgb = rgb;
+
+       return devm_led_classdev_register(&rgb->ldev->hdev->dev, &led->cdev);
+}
+
+static int hidled_init_rgb(struct hidled_rgb *rgb, unsigned int minor)
+{
+       int ret;
+
+       /* Register the red diode */
+       ret = hidled_init_led(&rgb->red, "red", rgb, minor);
+       if (ret)
+               return ret;
+
+       /* Register the green diode */
+       ret = hidled_init_led(&rgb->green, "green", rgb, minor);
+       if (ret)
+               return ret;
+
+       /* Register the blue diode */
+       return hidled_init_led(&rgb->blue, "blue", rgb, minor);
+}
+
+static int hidled_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       struct hidled_device *ldev;
+       unsigned int minor;
+       int ret, i;
+
+       ldev = devm_kzalloc(&hdev->dev, sizeof(*ldev), GFP_KERNEL);
+       if (!ldev)
+               return -ENOMEM;
+
+       ret = hid_parse(hdev);
+       if (ret)
+               return ret;
+
+       ldev->hdev = hdev;
+       mutex_init(&ldev->lock);
+
+       for (i = 0; !ldev->config && i < ARRAY_SIZE(hidled_configs); i++)
+               if (hidled_configs[i].type == id->driver_data)
+                       ldev->config = &hidled_configs[i];
+
+       if (!ldev->config)
+               return -EINVAL;
+
+       if (ldev->config->init) {
+               ret = ldev->config->init(ldev);
+               if (ret)
+                       return ret;
+       }
+
+       ldev->rgb = devm_kcalloc(&hdev->dev, ldev->config->num_leds,
+                                sizeof(struct hidled_rgb), GFP_KERNEL);
+       if (!ldev->rgb)
+               return -ENOMEM;
+
+       ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
+       if (ret)
+               return ret;
+
+       minor = ((struct hidraw *) hdev->hidraw)->minor;
+
+       for (i = 0; i < ldev->config->num_leds; i++) {
+               ldev->rgb[i].ldev = ldev;
+               ldev->rgb[i].num = i;
+               ret = hidled_init_rgb(&ldev->rgb[i], minor);
+               if (ret) {
+                       hid_hw_stop(hdev);
+                       return ret;
+               }
+       }
+
+       hid_info(hdev, "%s initialized\n", ldev->config->name);
+
+       return 0;
+}
+
+static const struct hid_device_id hidled_table[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_RISO_KAGAKU,
+         USB_DEVICE_ID_RI_KA_WEBMAIL), .driver_data = RISO_KAGAKU },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY,
+         USB_DEVICE_ID_DREAM_CHEEKY_WN), .driver_data = DREAM_CHEEKY },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY,
+         USB_DEVICE_ID_DREAM_CHEEKY_FA), .driver_data = DREAM_CHEEKY },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THINGM,
+         USB_DEVICE_ID_BLINK1), .driver_data = THINGM },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DELCOM,
+         USB_DEVICE_ID_DELCOM_VISUAL_IND), .driver_data = DELCOM },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP,
+         USB_DEVICE_ID_LUXAFOR), .driver_data = LUXAFOR },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, hidled_table);
+
+static struct hid_driver hidled_driver = {
+       .name = "hid-led",
+       .probe = hidled_probe,
+       .id_table = hidled_table,
+};
+
+module_hid_driver(hidled_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Heiner Kallweit <hkallweit1@gmail.com>");
+MODULE_DESCRIPTION("Simple USB RGB LED driver");
diff --git a/drivers/hid/hid-thingm.c b/drivers/hid/hid-thingm.c
deleted file mode 100644 (file)
index 9ad9c6e..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * ThingM blink(1) USB RGB LED driver
- *
- * Copyright 2013-2014 Savoir-faire Linux Inc.
- *     Vivien Didelot <vivien.didelot@savoirfairelinux.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2.
- */
-
-#include <linux/hid.h>
-#include <linux/hidraw.h>
-#include <linux/leds.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-
-#include "hid-ids.h"
-
-#define REPORT_ID      1
-#define REPORT_SIZE    9
-
-/* Firmware major number of supported devices */
-#define THINGM_MAJOR_MK1       '1'
-#define THINGM_MAJOR_MK2       '2'
-
-struct thingm_fwinfo {
-       char major;
-       unsigned numrgb;
-       unsigned first;
-};
-
-static const struct thingm_fwinfo thingm_fwinfo[] = {
-       {
-               .major = THINGM_MAJOR_MK1,
-               .numrgb = 1,
-               .first = 0,
-       }, {
-               .major = THINGM_MAJOR_MK2,
-               .numrgb = 2,
-               .first = 1,
-       }
-};
-
-/* A red, green or blue channel, part of an RGB chip */
-struct thingm_led {
-       struct thingm_rgb *rgb;
-       struct led_classdev ldev;
-       char name[32];
-};
-
-/* Basically a WS2812 5050 RGB LED chip */
-struct thingm_rgb {
-       struct thingm_device *tdev;
-       struct thingm_led red;
-       struct thingm_led green;
-       struct thingm_led blue;
-       u8 num;
-};
-
-struct thingm_device {
-       struct hid_device *hdev;
-       struct {
-               char major;
-               char minor;
-       } version;
-       const struct thingm_fwinfo *fwinfo;
-       struct mutex lock;
-       struct thingm_rgb *rgb;
-};
-
-static int thingm_send(struct thingm_device *tdev, u8 buf[REPORT_SIZE])
-{
-       int ret;
-
-       hid_dbg(tdev->hdev, "-> %d %c %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n",
-                       buf[0], buf[1], buf[2], buf[3], buf[4],
-                       buf[5], buf[6], buf[7], buf[8]);
-
-       mutex_lock(&tdev->lock);
-
-       ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
-                       HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
-
-       mutex_unlock(&tdev->lock);
-
-       return ret < 0 ? ret : 0;
-}
-
-static int thingm_recv(struct thingm_device *tdev, u8 buf[REPORT_SIZE])
-{
-       int ret;
-
-       /*
-        * A read consists of two operations: sending the read command
-        * and the actual read from the device. Use the mutex to protect
-        * the full sequence of both operations.
-        */
-       mutex_lock(&tdev->lock);
-
-       ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
-                       HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
-       if (ret < 0)
-               goto err;
-
-       ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
-                       HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
-       if (ret < 0)
-               goto err;
-
-       ret = 0;
-
-       hid_dbg(tdev->hdev, "<- %d %c %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n",
-                       buf[0], buf[1], buf[2], buf[3], buf[4],
-                       buf[5], buf[6], buf[7], buf[8]);
-err:
-       mutex_unlock(&tdev->lock);
-       return ret;
-}
-
-static int thingm_version(struct thingm_device *tdev)
-{
-       u8 buf[REPORT_SIZE] = { REPORT_ID, 'v', 0, 0, 0, 0, 0, 0, 0 };
-       int err;
-
-       err = thingm_recv(tdev, buf);
-       if (err)
-               return err;
-
-       tdev->version.major = buf[3];
-       tdev->version.minor = buf[4];
-
-       return 0;
-}
-
-static int thingm_write_color(struct thingm_rgb *rgb)
-{
-       u8 buf[REPORT_SIZE] = { REPORT_ID, 'c', 0, 0, 0, 0, 0, rgb->num, 0 };
-
-       buf[2] = rgb->red.ldev.brightness;
-       buf[3] = rgb->green.ldev.brightness;
-       buf[4] = rgb->blue.ldev.brightness;
-
-       return thingm_send(rgb->tdev, buf);
-}
-
-static int thingm_led_set(struct led_classdev *ldev,
-                         enum led_brightness brightness)
-{
-       struct thingm_led *led = container_of(ldev, struct thingm_led, ldev);
-
-       return thingm_write_color(led->rgb);
-}
-
-static int thingm_init_led(struct thingm_led *led, const char *color_name,
-                          struct thingm_rgb *rgb, int minor)
-{
-       snprintf(led->name, sizeof(led->name), "thingm%d:%s:led%d",
-                minor, color_name, rgb->num);
-       led->ldev.name = led->name;
-       led->ldev.max_brightness = 255;
-       led->ldev.brightness_set_blocking = thingm_led_set;
-       led->ldev.flags = LED_HW_PLUGGABLE;
-       led->rgb = rgb;
-       return devm_led_classdev_register(&rgb->tdev->hdev->dev, &led->ldev);
-}
-
-static int thingm_init_rgb(struct thingm_rgb *rgb)
-{
-       const int minor = ((struct hidraw *) rgb->tdev->hdev->hidraw)->minor;
-       int err;
-
-       /* Register the red diode */
-       err = thingm_init_led(&rgb->red, "red", rgb, minor);
-       if (err)
-               return err;
-
-       /* Register the green diode */
-       err = thingm_init_led(&rgb->green, "green", rgb, minor);
-       if (err)
-               return err;
-
-       /* Register the blue diode */
-       return thingm_init_led(&rgb->blue, "blue", rgb, minor);
-}
-
-static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id)
-{
-       struct thingm_device *tdev;
-       int i, err;
-
-       tdev = devm_kzalloc(&hdev->dev, sizeof(struct thingm_device),
-                       GFP_KERNEL);
-       if (!tdev)
-               return -ENOMEM;
-
-       tdev->hdev = hdev;
-       hid_set_drvdata(hdev, tdev);
-
-       err = hid_parse(hdev);
-       if (err)
-               return err;
-
-       mutex_init(&tdev->lock);
-
-       err = thingm_version(tdev);
-       if (err)
-               return err;
-
-       hid_dbg(hdev, "firmware version: %c.%c\n",
-                       tdev->version.major, tdev->version.minor);
-
-       for (i = 0; i < ARRAY_SIZE(thingm_fwinfo) && !tdev->fwinfo; ++i)
-               if (thingm_fwinfo[i].major == tdev->version.major)
-                       tdev->fwinfo = &thingm_fwinfo[i];
-
-       if (!tdev->fwinfo) {
-               hid_err(hdev, "unsupported firmware %c\n", tdev->version.major);
-               return -ENODEV;
-       }
-
-       tdev->rgb = devm_kzalloc(&hdev->dev,
-                       sizeof(struct thingm_rgb) * tdev->fwinfo->numrgb,
-                       GFP_KERNEL);
-       if (!tdev->rgb)
-               return -ENOMEM;
-
-       err = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
-       if (err)
-               return err;
-
-       for (i = 0; i < tdev->fwinfo->numrgb; ++i) {
-               struct thingm_rgb *rgb = tdev->rgb + i;
-
-               rgb->tdev = tdev;
-               rgb->num = tdev->fwinfo->first + i;
-               err = thingm_init_rgb(rgb);
-               if (err) {
-                       hid_hw_stop(hdev);
-                       return err;
-               }
-       }
-
-       return 0;
-}
-
-static const struct hid_device_id thingm_table[] = {
-       { HID_USB_DEVICE(USB_VENDOR_ID_THINGM, USB_DEVICE_ID_BLINK1) },
-       { }
-};
-MODULE_DEVICE_TABLE(hid, thingm_table);
-
-static struct hid_driver thingm_driver = {
-       .name = "thingm",
-       .probe = thingm_probe,
-       .id_table = thingm_table,
-};
-
-module_hid_driver(thingm_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Vivien Didelot <vivien.didelot@savoirfairelinux.com>");
-MODULE_DESCRIPTION("ThingM blink(1) USB RGB LED driver");
index 2e021ba..b3ec4f2 100644 (file)
@@ -1020,6 +1020,7 @@ static int i2c_hid_probe(struct i2c_client *client,
        pm_runtime_get_noresume(&client->dev);
        pm_runtime_set_active(&client->dev);
        pm_runtime_enable(&client->dev);
+       device_enable_async_suspend(&client->dev);
 
        ret = i2c_hid_fetch_hid_descriptor(ihid);
        if (ret < 0)
@@ -1106,6 +1107,14 @@ static int i2c_hid_remove(struct i2c_client *client)
        return 0;
 }
 
+static void i2c_hid_shutdown(struct i2c_client *client)
+{
+       struct i2c_hid *ihid = i2c_get_clientdata(client);
+
+       i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
+       free_irq(client->irq, ihid);
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int i2c_hid_suspend(struct device *dev)
 {
@@ -1230,7 +1239,7 @@ static struct i2c_driver i2c_hid_driver = {
 
        .probe          = i2c_hid_probe,
        .remove         = i2c_hid_remove,
-
+       .shutdown       = i2c_hid_shutdown,
        .id_table       = i2c_hid_id_table,
 };
 
index 16b6f11..99ec3ff 100644 (file)
@@ -51,10 +51,26 @@ struct uhid_device {
        u32 report_id;
        u32 report_type;
        struct uhid_event report_buf;
+       struct work_struct worker;
 };
 
 static struct miscdevice uhid_misc;
 
+static void uhid_device_add_worker(struct work_struct *work)
+{
+       struct uhid_device *uhid = container_of(work, struct uhid_device, worker);
+       int ret;
+
+       ret = hid_add_device(uhid->hid);
+       if (ret) {
+               hid_err(uhid->hid, "Cannot register HID device: error %d\n", ret);
+
+               hid_destroy_device(uhid->hid);
+               uhid->hid = NULL;
+               uhid->running = false;
+       }
+}
+
 static void uhid_queue(struct uhid_device *uhid, struct uhid_event *ev)
 {
        __u8 newhead;
@@ -498,18 +514,14 @@ static int uhid_dev_create2(struct uhid_device *uhid,
        uhid->hid = hid;
        uhid->running = true;
 
-       ret = hid_add_device(hid);
-       if (ret) {
-               hid_err(hid, "Cannot register HID device\n");
-               goto err_hid;
-       }
+       /* Adding of a HID device is done through a worker, to allow HID drivers
+        * which use feature requests during .probe to work, without they would
+        * be blocked on devlock, which is held by uhid_char_write.
+        */
+       schedule_work(&uhid->worker);
 
        return 0;
 
-err_hid:
-       hid_destroy_device(hid);
-       uhid->hid = NULL;
-       uhid->running = false;
 err_free:
        kfree(uhid->rd_data);
        uhid->rd_data = NULL;
@@ -550,6 +562,8 @@ static int uhid_dev_destroy(struct uhid_device *uhid)
        uhid->running = false;
        wake_up_interruptible(&uhid->report_wait);
 
+       cancel_work_sync(&uhid->worker);
+
        hid_destroy_device(uhid->hid);
        kfree(uhid->rd_data);
 
@@ -612,6 +626,7 @@ static int uhid_char_open(struct inode *inode, struct file *file)
        init_waitqueue_head(&uhid->waitq);
        init_waitqueue_head(&uhid->report_wait);
        uhid->running = false;
+       INIT_WORK(&uhid->worker, uhid_device_add_worker);
 
        file->private_data = uhid;
        nonseekable_open(inode, file);
index c752447..fa6880b 100644 (file)
@@ -98,6 +98,7 @@ static int qcom_hwspinlock_probe(struct platform_device *pdev)
        }
 
        regmap = syscon_node_to_regmap(syscon);
+       of_node_put(syscon);
        if (IS_ERR(regmap))
                return PTR_ERR(regmap);
 
index 6d35dd4..4788b0b 100644 (file)
@@ -142,7 +142,7 @@ static int linear_iterate_devices(struct dm_target *ti,
 }
 
 static long linear_direct_access(struct dm_target *ti, sector_t sector,
-                                void __pmem **kaddr, pfn_t *pfn, long size)
+                                void **kaddr, pfn_t *pfn, long size)
 {
        struct linear_c *lc = ti->private;
        struct block_device *bdev = lc->dev->bdev;
index 731e1f5..ce2a910 100644 (file)
@@ -2303,7 +2303,7 @@ static int origin_map(struct dm_target *ti, struct bio *bio)
 }
 
 static long origin_direct_access(struct dm_target *ti, sector_t sector,
-               void __pmem **kaddr, pfn_t *pfn, long size)
+               void **kaddr, pfn_t *pfn, long size)
 {
        DMWARN("device does not support dax.");
        return -EIO;
index 01bb9cf..83f1d46 100644 (file)
@@ -309,7 +309,7 @@ static int stripe_map(struct dm_target *ti, struct bio *bio)
 }
 
 static long stripe_direct_access(struct dm_target *ti, sector_t sector,
-                                void __pmem **kaddr, pfn_t *pfn, long size)
+                                void **kaddr, pfn_t *pfn, long size)
 {
        struct stripe_c *sc = ti->private;
        uint32_t stripe;
index 6eecd6b..710ae28 100644 (file)
@@ -149,7 +149,7 @@ static void io_err_release_clone_rq(struct request *clone)
 }
 
 static long io_err_direct_access(struct dm_target *ti, sector_t sector,
-                                void __pmem **kaddr, pfn_t *pfn, long size)
+                                void **kaddr, pfn_t *pfn, long size)
 {
        return -EIO;
 }
index ceb69fc..25d1d97 100644 (file)
@@ -906,7 +906,7 @@ int dm_set_target_max_io_len(struct dm_target *ti, sector_t len)
 EXPORT_SYMBOL_GPL(dm_set_target_max_io_len);
 
 static long dm_blk_direct_access(struct block_device *bdev, sector_t sector,
-                                void __pmem **kaddr, pfn_t *pfn, long size)
+                                void **kaddr, pfn_t *pfn, long size)
 {
        struct mapped_device *md = bdev->bd_disk->private_data;
        struct dm_table *map;
index 7c8a3bf..124c243 100644 (file)
@@ -1,6 +1,7 @@
 menuconfig LIBNVDIMM
        tristate "NVDIMM (Non-Volatile Memory Device) Support"
        depends on PHYS_ADDR_T_64BIT
+       depends on HAS_IOMEM
        depends on BLK_DEV
        help
          Generic support for non-volatile memory devices including
@@ -19,7 +20,6 @@ if LIBNVDIMM
 config BLK_DEV_PMEM
        tristate "PMEM: Persistent memory block device support"
        default LIBNVDIMM
-       depends on HAS_IOMEM
        select ND_BTT if BTT
        select ND_PFN if NVDIMM_PFN
        help
index 7e262ef..9faaa96 100644 (file)
@@ -267,10 +267,8 @@ static int nsblk_attach_disk(struct nd_namespace_blk *nsblk)
        q = blk_alloc_queue(GFP_KERNEL);
        if (!q)
                return -ENOMEM;
-       if (devm_add_action(dev, nd_blk_release_queue, q)) {
-               blk_cleanup_queue(q);
+       if (devm_add_action_or_reset(dev, nd_blk_release_queue, q))
                return -ENOMEM;
-       }
 
        blk_queue_make_request(q, nd_blk_make_request);
        blk_queue_max_hw_sectors(q, UINT_MAX);
@@ -282,10 +280,6 @@ static int nsblk_attach_disk(struct nd_namespace_blk *nsblk)
        disk = alloc_disk(0);
        if (!disk)
                return -ENOMEM;
-       if (devm_add_action(dev, nd_blk_release_disk, disk)) {
-               put_disk(disk);
-               return -ENOMEM;
-       }
 
        disk->first_minor       = 0;
        disk->fops              = &nd_blk_fops;
@@ -295,6 +289,9 @@ static int nsblk_attach_disk(struct nd_namespace_blk *nsblk)
        set_capacity(disk, 0);
        device_add_disk(dev, disk);
 
+       if (devm_add_action_or_reset(dev, nd_blk_release_disk, disk))
+               return -ENOMEM;
+
        if (nsblk_meta_size(nsblk)) {
                int rc = nd_integrity_init(disk, nsblk_meta_size(nsblk));
 
index 816d0da..3fa7919 100644 (file)
@@ -198,8 +198,7 @@ struct device *nd_btt_create(struct nd_region *nd_region)
 {
        struct device *dev = __nd_btt_create(nd_region, 0, NULL, NULL);
 
-       if (dev)
-               __nd_device_register(dev);
+       __nd_device_register(dev);
        return dev;
 }
 
index 5e4e5c7..458daf9 100644 (file)
@@ -31,6 +31,7 @@
 int nvdimm_major;
 static int nvdimm_bus_major;
 static struct class *nd_class;
+static DEFINE_IDA(nd_ida);
 
 static int to_nd_device_type(struct device *dev)
 {
@@ -60,20 +61,13 @@ static int nvdimm_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
                        to_nd_device_type(dev));
 }
 
-static int nvdimm_bus_match(struct device *dev, struct device_driver *drv)
-{
-       struct nd_device_driver *nd_drv = to_nd_device_driver(drv);
-
-       return !!test_bit(to_nd_device_type(dev), &nd_drv->type);
-}
-
 static struct module *to_bus_provider(struct device *dev)
 {
        /* pin bus providers while regions are enabled */
        if (is_nd_pmem(dev) || is_nd_blk(dev)) {
                struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
 
-               return nvdimm_bus->module;
+               return nvdimm_bus->nd_desc->module;
        }
        return NULL;
 }
@@ -136,6 +130,21 @@ static int nvdimm_bus_remove(struct device *dev)
        return rc;
 }
 
+static void nvdimm_bus_shutdown(struct device *dev)
+{
+       struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
+       struct nd_device_driver *nd_drv = NULL;
+
+       if (dev->driver)
+               nd_drv = to_nd_device_driver(dev->driver);
+
+       if (nd_drv && nd_drv->shutdown) {
+               nd_drv->shutdown(dev);
+               dev_dbg(&nvdimm_bus->dev, "%s.shutdown(%s)\n",
+                               dev->driver->name, dev_name(dev));
+       }
+}
+
 void nd_device_notify(struct device *dev, enum nvdimm_event event)
 {
        device_lock(dev);
@@ -208,14 +217,187 @@ long nvdimm_clear_poison(struct device *dev, phys_addr_t phys,
 }
 EXPORT_SYMBOL_GPL(nvdimm_clear_poison);
 
+static int nvdimm_bus_match(struct device *dev, struct device_driver *drv);
+
 static struct bus_type nvdimm_bus_type = {
        .name = "nd",
        .uevent = nvdimm_bus_uevent,
        .match = nvdimm_bus_match,
        .probe = nvdimm_bus_probe,
        .remove = nvdimm_bus_remove,
+       .shutdown = nvdimm_bus_shutdown,
+};
+
+static void nvdimm_bus_release(struct device *dev)
+{
+       struct nvdimm_bus *nvdimm_bus;
+
+       nvdimm_bus = container_of(dev, struct nvdimm_bus, dev);
+       ida_simple_remove(&nd_ida, nvdimm_bus->id);
+       kfree(nvdimm_bus);
+}
+
+static bool is_nvdimm_bus(struct device *dev)
+{
+       return dev->release == nvdimm_bus_release;
+}
+
+struct nvdimm_bus *walk_to_nvdimm_bus(struct device *nd_dev)
+{
+       struct device *dev;
+
+       for (dev = nd_dev; dev; dev = dev->parent)
+               if (is_nvdimm_bus(dev))
+                       break;
+       dev_WARN_ONCE(nd_dev, !dev, "invalid dev, not on nd bus\n");
+       if (dev)
+               return to_nvdimm_bus(dev);
+       return NULL;
+}
+
+struct nvdimm_bus *to_nvdimm_bus(struct device *dev)
+{
+       struct nvdimm_bus *nvdimm_bus;
+
+       nvdimm_bus = container_of(dev, struct nvdimm_bus, dev);
+       WARN_ON(!is_nvdimm_bus(dev));
+       return nvdimm_bus;
+}
+EXPORT_SYMBOL_GPL(to_nvdimm_bus);
+
+struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
+               struct nvdimm_bus_descriptor *nd_desc)
+{
+       struct nvdimm_bus *nvdimm_bus;
+       int rc;
+
+       nvdimm_bus = kzalloc(sizeof(*nvdimm_bus), GFP_KERNEL);
+       if (!nvdimm_bus)
+               return NULL;
+       INIT_LIST_HEAD(&nvdimm_bus->list);
+       INIT_LIST_HEAD(&nvdimm_bus->mapping_list);
+       INIT_LIST_HEAD(&nvdimm_bus->poison_list);
+       init_waitqueue_head(&nvdimm_bus->probe_wait);
+       nvdimm_bus->id = ida_simple_get(&nd_ida, 0, 0, GFP_KERNEL);
+       mutex_init(&nvdimm_bus->reconfig_mutex);
+       if (nvdimm_bus->id < 0) {
+               kfree(nvdimm_bus);
+               return NULL;
+       }
+       nvdimm_bus->nd_desc = nd_desc;
+       nvdimm_bus->dev.parent = parent;
+       nvdimm_bus->dev.release = nvdimm_bus_release;
+       nvdimm_bus->dev.groups = nd_desc->attr_groups;
+       nvdimm_bus->dev.bus = &nvdimm_bus_type;
+       dev_set_name(&nvdimm_bus->dev, "ndbus%d", nvdimm_bus->id);
+       rc = device_register(&nvdimm_bus->dev);
+       if (rc) {
+               dev_dbg(&nvdimm_bus->dev, "registration failed: %d\n", rc);
+               goto err;
+       }
+
+       return nvdimm_bus;
+ err:
+       put_device(&nvdimm_bus->dev);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(nvdimm_bus_register);
+
+void nvdimm_bus_unregister(struct nvdimm_bus *nvdimm_bus)
+{
+       if (!nvdimm_bus)
+               return;
+       device_unregister(&nvdimm_bus->dev);
+}
+EXPORT_SYMBOL_GPL(nvdimm_bus_unregister);
+
+static int child_unregister(struct device *dev, void *data)
+{
+       /*
+        * the singular ndctl class device per bus needs to be
+        * "device_destroy"ed, so skip it here
+        *
+        * i.e. remove classless children
+        */
+       if (dev->class)
+               /* pass */;
+       else
+               nd_device_unregister(dev, ND_SYNC);
+       return 0;
+}
+
+static void free_poison_list(struct list_head *poison_list)
+{
+       struct nd_poison *pl, *next;
+
+       list_for_each_entry_safe(pl, next, poison_list, list) {
+               list_del(&pl->list);
+               kfree(pl);
+       }
+       list_del_init(poison_list);
+}
+
+static int nd_bus_remove(struct device *dev)
+{
+       struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
+
+       mutex_lock(&nvdimm_bus_list_mutex);
+       list_del_init(&nvdimm_bus->list);
+       mutex_unlock(&nvdimm_bus_list_mutex);
+
+       nd_synchronize();
+       device_for_each_child(&nvdimm_bus->dev, NULL, child_unregister);
+
+       nvdimm_bus_lock(&nvdimm_bus->dev);
+       free_poison_list(&nvdimm_bus->poison_list);
+       nvdimm_bus_unlock(&nvdimm_bus->dev);
+
+       nvdimm_bus_destroy_ndctl(nvdimm_bus);
+
+       return 0;
+}
+
+static int nd_bus_probe(struct device *dev)
+{
+       struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
+       int rc;
+
+       rc = nvdimm_bus_create_ndctl(nvdimm_bus);
+       if (rc)
+               return rc;
+
+       mutex_lock(&nvdimm_bus_list_mutex);
+       list_add_tail(&nvdimm_bus->list, &nvdimm_bus_list);
+       mutex_unlock(&nvdimm_bus_list_mutex);
+
+       /* enable bus provider attributes to look up their local context */
+       dev_set_drvdata(dev, nvdimm_bus->nd_desc);
+
+       return 0;
+}
+
+static struct nd_device_driver nd_bus_driver = {
+       .probe = nd_bus_probe,
+       .remove = nd_bus_remove,
+       .drv = {
+               .name = "nd_bus",
+               .suppress_bind_attrs = true,
+               .bus = &nvdimm_bus_type,
+               .owner = THIS_MODULE,
+               .mod_name = KBUILD_MODNAME,
+       },
 };
 
+static int nvdimm_bus_match(struct device *dev, struct device_driver *drv)
+{
+       struct nd_device_driver *nd_drv = to_nd_device_driver(drv);
+
+       if (is_nvdimm_bus(dev) && nd_drv == &nd_bus_driver)
+               return true;
+
+       return !!test_bit(to_nd_device_type(dev), &nd_drv->type);
+}
+
 static ASYNC_DOMAIN_EXCLUSIVE(nd_async_domain);
 
 void nd_synchronize(void)
@@ -395,12 +577,10 @@ int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus)
        dev = device_create(nd_class, &nvdimm_bus->dev, devt, nvdimm_bus,
                        "ndctl%d", nvdimm_bus->id);
 
-       if (IS_ERR(dev)) {
+       if (IS_ERR(dev))
                dev_dbg(&nvdimm_bus->dev, "failed to register ndctl%d: %ld\n",
                                nvdimm_bus->id, PTR_ERR(dev));
-               return PTR_ERR(dev);
-       }
-       return 0;
+       return PTR_ERR_OR_ZERO(dev);
 }
 
 void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus)
@@ -850,8 +1030,14 @@ int __init nvdimm_bus_init(void)
                goto err_class;
        }
 
+       rc = driver_register(&nd_bus_driver.drv);
+       if (rc)
+               goto err_nd_bus;
+
        return 0;
 
+ err_nd_bus:
+       class_destroy(nd_class);
  err_class:
        unregister_chrdev(nvdimm_major, "dimmctl");
  err_dimm_chrdev:
@@ -864,8 +1050,10 @@ int __init nvdimm_bus_init(void)
 
 void nvdimm_bus_exit(void)
 {
+       driver_unregister(&nd_bus_driver.drv);
        class_destroy(nd_class);
        unregister_chrdev(nvdimm_bus_major, "ndctl");
        unregister_chrdev(nvdimm_major, "dimmctl");
        bus_unregister(&nvdimm_bus_type);
+       ida_destroy(&nd_ida);
 }
index 8b2e3c4..d5dc80c 100644 (file)
@@ -240,7 +240,7 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,
                return memcpy_from_pmem(buf, nsio->addr + offset, size);
        } else {
                memcpy_to_pmem(nsio->addr + offset, buf, size);
-               wmb_pmem();
+               nvdimm_flush(to_nd_region(ndns->dev.parent));
        }
 
        return 0;
@@ -266,9 +266,8 @@ int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio)
 
        nsio->addr = devm_memremap(dev, res->start, resource_size(res),
                        ARCH_MEMREMAP_PMEM);
-       if (IS_ERR(nsio->addr))
-               return PTR_ERR(nsio->addr);
-       return 0;
+
+       return PTR_ERR_OR_ZERO(nsio->addr);
 }
 EXPORT_SYMBOL_GPL(devm_nsio_enable);
 
index be89764..715583f 100644 (file)
 #include <linux/ndctl.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 #include "nd-core.h"
 #include "nd.h"
 
 LIST_HEAD(nvdimm_bus_list);
 DEFINE_MUTEX(nvdimm_bus_list_mutex);
-static DEFINE_IDA(nd_ida);
 
 void nvdimm_bus_lock(struct device *dev)
 {
@@ -57,6 +57,127 @@ bool is_nvdimm_bus_locked(struct device *dev)
 }
 EXPORT_SYMBOL(is_nvdimm_bus_locked);
 
+struct nvdimm_map {
+       struct nvdimm_bus *nvdimm_bus;
+       struct list_head list;
+       resource_size_t offset;
+       unsigned long flags;
+       size_t size;
+       union {
+               void *mem;
+               void __iomem *iomem;
+       };
+       struct kref kref;
+};
+
+static struct nvdimm_map *find_nvdimm_map(struct device *dev,
+               resource_size_t offset)
+{
+       struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
+       struct nvdimm_map *nvdimm_map;
+
+       list_for_each_entry(nvdimm_map, &nvdimm_bus->mapping_list, list)
+               if (nvdimm_map->offset == offset)
+                       return nvdimm_map;
+       return NULL;
+}
+
+static struct nvdimm_map *alloc_nvdimm_map(struct device *dev,
+               resource_size_t offset, size_t size, unsigned long flags)
+{
+       struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
+       struct nvdimm_map *nvdimm_map;
+
+       nvdimm_map = kzalloc(sizeof(*nvdimm_map), GFP_KERNEL);
+       if (!nvdimm_map)
+               return NULL;
+
+       INIT_LIST_HEAD(&nvdimm_map->list);
+       nvdimm_map->nvdimm_bus = nvdimm_bus;
+       nvdimm_map->offset = offset;
+       nvdimm_map->flags = flags;
+       nvdimm_map->size = size;
+       kref_init(&nvdimm_map->kref);
+
+       if (!request_mem_region(offset, size, dev_name(&nvdimm_bus->dev)))
+               goto err_request_region;
+
+       if (flags)
+               nvdimm_map->mem = memremap(offset, size, flags);
+       else
+               nvdimm_map->iomem = ioremap(offset, size);
+
+       if (!nvdimm_map->mem)
+               goto err_map;
+
+       dev_WARN_ONCE(dev, !is_nvdimm_bus_locked(dev), "%s: bus unlocked!",
+                       __func__);
+       list_add(&nvdimm_map->list, &nvdimm_bus->mapping_list);
+
+       return nvdimm_map;
+
+ err_map:
+       release_mem_region(offset, size);
+ err_request_region:
+       kfree(nvdimm_map);
+       return NULL;
+}
+
+static void nvdimm_map_release(struct kref *kref)
+{
+       struct nvdimm_bus *nvdimm_bus;
+       struct nvdimm_map *nvdimm_map;
+
+       nvdimm_map = container_of(kref, struct nvdimm_map, kref);
+       nvdimm_bus = nvdimm_map->nvdimm_bus;
+
+       dev_dbg(&nvdimm_bus->dev, "%s: %pa\n", __func__, &nvdimm_map->offset);
+       list_del(&nvdimm_map->list);
+       if (nvdimm_map->flags)
+               memunmap(nvdimm_map->mem);
+       else
+               iounmap(nvdimm_map->iomem);
+       release_mem_region(nvdimm_map->offset, nvdimm_map->size);
+       kfree(nvdimm_map);
+}
+
+static void nvdimm_map_put(void *data)
+{
+       struct nvdimm_map *nvdimm_map = data;
+       struct nvdimm_bus *nvdimm_bus = nvdimm_map->nvdimm_bus;
+
+       nvdimm_bus_lock(&nvdimm_bus->dev);
+       kref_put(&nvdimm_map->kref, nvdimm_map_release);
+       nvdimm_bus_unlock(&nvdimm_bus->dev);
+}
+
+/**
+ * devm_nvdimm_memremap - map a resource that is shared across regions
+ * @dev: device that will own a reference to the shared mapping
+ * @offset: physical base address of the mapping
+ * @size: mapping size
+ * @flags: memremap flags, or, if zero, perform an ioremap instead
+ */
+void *devm_nvdimm_memremap(struct device *dev, resource_size_t offset,
+               size_t size, unsigned long flags)
+{
+       struct nvdimm_map *nvdimm_map;
+
+       nvdimm_bus_lock(dev);
+       nvdimm_map = find_nvdimm_map(dev, offset);
+       if (!nvdimm_map)
+               nvdimm_map = alloc_nvdimm_map(dev, offset, size, flags);
+       else
+               kref_get(&nvdimm_map->kref);
+       nvdimm_bus_unlock(dev);
+
+       if (devm_add_action_or_reset(dev, nvdimm_map_put, nvdimm_map))
+               return NULL;
+
+       return nvdimm_map->mem;
+}
+EXPORT_SYMBOL_GPL(devm_nvdimm_memremap);
+
 u64 nd_fletcher64(void *addr, size_t len, bool le)
 {
        u32 *buf = addr;
@@ -73,25 +194,6 @@ u64 nd_fletcher64(void *addr, size_t len, bool le)
 }
 EXPORT_SYMBOL_GPL(nd_fletcher64);
 
-static void nvdimm_bus_release(struct device *dev)
-{
-       struct nvdimm_bus *nvdimm_bus;
-
-       nvdimm_bus = container_of(dev, struct nvdimm_bus, dev);
-       ida_simple_remove(&nd_ida, nvdimm_bus->id);
-       kfree(nvdimm_bus);
-}
-
-struct nvdimm_bus *to_nvdimm_bus(struct device *dev)
-{
-       struct nvdimm_bus *nvdimm_bus;
-
-       nvdimm_bus = container_of(dev, struct nvdimm_bus, dev);
-       WARN_ON(nvdimm_bus->dev.release != nvdimm_bus_release);
-       return nvdimm_bus;
-}
-EXPORT_SYMBOL_GPL(to_nvdimm_bus);
-
 struct nvdimm_bus_descriptor *to_nd_desc(struct nvdimm_bus *nvdimm_bus)
 {
        /* struct nvdimm_bus definition is private to libnvdimm */
@@ -99,18 +201,12 @@ struct nvdimm_bus_descriptor *to_nd_desc(struct nvdimm_bus *nvdimm_bus)
 }
 EXPORT_SYMBOL_GPL(to_nd_desc);
 
-struct nvdimm_bus *walk_to_nvdimm_bus(struct device *nd_dev)
+struct device *to_nvdimm_bus_dev(struct nvdimm_bus *nvdimm_bus)
 {
-       struct device *dev;
-
-       for (dev = nd_dev; dev; dev = dev->parent)
-               if (dev->release == nvdimm_bus_release)
-                       break;
-       dev_WARN_ONCE(nd_dev, !dev, "invalid dev, not on nd bus\n");
-       if (dev)
-               return to_nvdimm_bus(dev);
-       return NULL;
+       /* struct nvdimm_bus definition is private to libnvdimm */
+       return &nvdimm_bus->dev;
 }
+EXPORT_SYMBOL_GPL(to_nvdimm_bus_dev);
 
 static bool is_uuid_sep(char sep)
 {
@@ -325,51 +421,6 @@ struct attribute_group nvdimm_bus_attribute_group = {
 };
 EXPORT_SYMBOL_GPL(nvdimm_bus_attribute_group);
 
-struct nvdimm_bus *__nvdimm_bus_register(struct device *parent,
-               struct nvdimm_bus_descriptor *nd_desc, struct module *module)
-{
-       struct nvdimm_bus *nvdimm_bus;
-       int rc;
-
-       nvdimm_bus = kzalloc(sizeof(*nvdimm_bus), GFP_KERNEL);
-       if (!nvdimm_bus)
-               return NULL;
-       INIT_LIST_HEAD(&nvdimm_bus->list);
-       INIT_LIST_HEAD(&nvdimm_bus->poison_list);
-       init_waitqueue_head(&nvdimm_bus->probe_wait);
-       nvdimm_bus->id = ida_simple_get(&nd_ida, 0, 0, GFP_KERNEL);
-       mutex_init(&nvdimm_bus->reconfig_mutex);
-       if (nvdimm_bus->id < 0) {
-               kfree(nvdimm_bus);
-               return NULL;
-       }
-       nvdimm_bus->nd_desc = nd_desc;
-       nvdimm_bus->module = module;
-       nvdimm_bus->dev.parent = parent;
-       nvdimm_bus->dev.release = nvdimm_bus_release;
-       nvdimm_bus->dev.groups = nd_desc->attr_groups;
-       dev_set_name(&nvdimm_bus->dev, "ndbus%d", nvdimm_bus->id);
-       rc = device_register(&nvdimm_bus->dev);
-       if (rc) {
-               dev_dbg(&nvdimm_bus->dev, "registration failed: %d\n", rc);
-               goto err;
-       }
-
-       rc = nvdimm_bus_create_ndctl(nvdimm_bus);
-       if (rc)
-               goto err;
-
-       mutex_lock(&nvdimm_bus_list_mutex);
-       list_add_tail(&nvdimm_bus->list, &nvdimm_bus_list);
-       mutex_unlock(&nvdimm_bus_list_mutex);
-
-       return nvdimm_bus;
- err:
-       put_device(&nvdimm_bus->dev);
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(__nvdimm_bus_register);
-
 static void set_badblock(struct badblocks *bb, sector_t s, int num)
 {
        dev_dbg(bb->dev, "Found a poison range (0x%llx, 0x%llx)\n",
@@ -545,54 +596,6 @@ int nvdimm_bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
 }
 EXPORT_SYMBOL_GPL(nvdimm_bus_add_poison);
 
-static void free_poison_list(struct list_head *poison_list)
-{
-       struct nd_poison *pl, *next;
-
-       list_for_each_entry_safe(pl, next, poison_list, list) {
-               list_del(&pl->list);
-               kfree(pl);
-       }
-       list_del_init(poison_list);
-}
-
-static int child_unregister(struct device *dev, void *data)
-{
-       /*
-        * the singular ndctl class device per bus needs to be
-        * "device_destroy"ed, so skip it here
-        *
-        * i.e. remove classless children
-        */
-       if (dev->class)
-               /* pass */;
-       else
-               nd_device_unregister(dev, ND_SYNC);
-       return 0;
-}
-
-void nvdimm_bus_unregister(struct nvdimm_bus *nvdimm_bus)
-{
-       if (!nvdimm_bus)
-               return;
-
-       mutex_lock(&nvdimm_bus_list_mutex);
-       list_del_init(&nvdimm_bus->list);
-       mutex_unlock(&nvdimm_bus_list_mutex);
-
-       nd_synchronize();
-       device_for_each_child(&nvdimm_bus->dev, NULL, child_unregister);
-
-       nvdimm_bus_lock(&nvdimm_bus->dev);
-       free_poison_list(&nvdimm_bus->poison_list);
-       nvdimm_bus_unlock(&nvdimm_bus->dev);
-
-       nvdimm_bus_destroy_ndctl(nvdimm_bus);
-
-       device_unregister(&nvdimm_bus->dev);
-}
-EXPORT_SYMBOL_GPL(nvdimm_bus_unregister);
-
 #ifdef CONFIG_BLK_DEV_INTEGRITY
 int nd_integrity_init(struct gendisk *disk, unsigned long meta_size)
 {
@@ -601,7 +604,8 @@ int nd_integrity_init(struct gendisk *disk, unsigned long meta_size)
        if (meta_size == 0)
                return 0;
 
-       bi.profile = NULL;
+       memset(&bi, 0, sizeof(bi));
+
        bi.tuple_size = meta_size;
        bi.tag_size = meta_size;
 
@@ -650,7 +654,6 @@ static __exit void libnvdimm_exit(void)
        nvdimm_bus_exit();
        nd_region_devs_exit();
        nvdimm_devs_exit();
-       ida_destroy(&nd_ida);
 }
 
 MODULE_LICENSE("GPL v2");
index bbde28d..d9bba5e 100644 (file)
@@ -346,7 +346,8 @@ EXPORT_SYMBOL_GPL(nvdimm_attribute_group);
 
 struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data,
                const struct attribute_group **groups, unsigned long flags,
-               unsigned long cmd_mask)
+               unsigned long cmd_mask, int num_flush,
+               struct resource *flush_wpq)
 {
        struct nvdimm *nvdimm = kzalloc(sizeof(*nvdimm), GFP_KERNEL);
        struct device *dev;
@@ -362,6 +363,8 @@ struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data,
        nvdimm->provider_data = provider_data;
        nvdimm->flags = flags;
        nvdimm->cmd_mask = cmd_mask;
+       nvdimm->num_flush = num_flush;
+       nvdimm->flush_wpq = flush_wpq;
        atomic_set(&nvdimm->busy, 0);
        dev = &nvdimm->dev;
        dev_set_name(dev, "nmem%d", nvdimm->id);
index 95825b3..11ea901 100644 (file)
@@ -47,6 +47,7 @@ static int e820_pmem_probe(struct platform_device *pdev)
 
        nd_desc.attr_groups = e820_pmem_attribute_groups;
        nd_desc.provider_name = "e820";
+       nd_desc.module = THIS_MODULE;
        nvdimm_bus = nvdimm_bus_register(dev, &nd_desc);
        if (!nvdimm_bus)
                goto err;
index 284cdaa..38ce6bb 100644 (file)
@@ -26,11 +26,11 @@ extern int nvdimm_major;
 struct nvdimm_bus {
        struct nvdimm_bus_descriptor *nd_desc;
        wait_queue_head_t probe_wait;
-       struct module *module;
        struct list_head list;
        struct device dev;
        int id, probe_active;
        struct list_head poison_list;
+       struct list_head mapping_list;
        struct mutex reconfig_mutex;
 };
 
@@ -40,7 +40,8 @@ struct nvdimm {
        unsigned long cmd_mask;
        struct device dev;
        atomic_t busy;
-       int id;
+       int id, num_flush;
+       struct resource *flush_wpq;
 };
 
 bool is_nvdimm(struct device *dev);
index d0ac93c..4047639 100644 (file)
@@ -49,9 +49,11 @@ struct nvdimm_drvdata {
        struct kref kref;
 };
 
-struct nd_region_namespaces {
-       int count;
-       int active;
+struct nd_region_data {
+       int ns_count;
+       int ns_active;
+       unsigned int flush_mask;
+       void __iomem *flush_wpq[0][0];
 };
 
 static inline struct nd_namespace_index *to_namespace_index(
@@ -119,7 +121,6 @@ struct nd_region {
 
 struct nd_blk_region {
        int (*enable)(struct nvdimm_bus *nvdimm_bus, struct device *dev);
-       void (*disable)(struct nvdimm_bus *nvdimm_bus, struct device *dev);
        int (*do_io)(struct nd_blk_region *ndbr, resource_size_t dpa,
                        void *iobuf, u64 len, int rw);
        void *blk_provider_data;
@@ -325,6 +326,7 @@ static inline void devm_nsio_disable(struct device *dev,
 }
 #endif
 int nd_blk_region_init(struct nd_region *nd_region);
+int nd_region_activate(struct nd_region *nd_region);
 void __nd_iostat_start(struct bio *bio, unsigned long *start);
 static inline bool nd_iostat_start(struct bio *bio, unsigned long *start)
 {
index 36cb390..b511099 100644 (file)
 #include <linux/slab.h>
 #include <linux/pmem.h>
 #include <linux/nd.h>
+#include "pmem.h"
 #include "pfn.h"
 #include "nd.h"
 
-struct pmem_device {
-       /* One contiguous memory region per device */
-       phys_addr_t             phys_addr;
-       /* when non-zero this device is hosting a 'pfn' instance */
-       phys_addr_t             data_offset;
-       u64                     pfn_flags;
-       void __pmem             *virt_addr;
-       /* immutable base size of the namespace */
-       size_t                  size;
-       /* trim size when namespace capacity has been section aligned */
-       u32                     pfn_pad;
-       struct badblocks        bb;
-};
+static struct device *to_dev(struct pmem_device *pmem)
+{
+       /*
+        * nvdimm bus services need a 'dev' parameter, and we record the device
+        * at init in bb.dev.
+        */
+       return pmem->bb.dev;
+}
+
+static struct nd_region *to_region(struct pmem_device *pmem)
+{
+       return to_nd_region(to_dev(pmem)->parent);
+}
 
 static void pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset,
                unsigned int len)
 {
-       struct device *dev = pmem->bb.dev;
+       struct device *dev = to_dev(pmem);
        sector_t sector;
        long cleared;
 
@@ -57,7 +58,7 @@ static void pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset,
        cleared = nvdimm_clear_poison(dev, pmem->phys_addr + offset, len);
 
        if (cleared > 0 && cleared / 512) {
-               dev_dbg(dev, "%s: %llx clear %ld sector%s\n",
+               dev_dbg(dev, "%s: %#llx clear %ld sector%s\n",
                                __func__, (unsigned long long) sector,
                                cleared / 512, cleared / 512 > 1 ? "s" : "");
                badblocks_clear(&pmem->bb, sector, cleared / 512);
@@ -73,7 +74,7 @@ static int pmem_do_bvec(struct pmem_device *pmem, struct page *page,
        bool bad_pmem = false;
        void *mem = kmap_atomic(page);
        phys_addr_t pmem_off = sector * 512 + pmem->data_offset;
-       void __pmem *pmem_addr = pmem->virt_addr + pmem_off;
+       void *pmem_addr = pmem->virt_addr + pmem_off;
 
        if (unlikely(is_bad_pmem(&pmem->bb, sector, len)))
                bad_pmem = true;
@@ -112,6 +113,11 @@ static int pmem_do_bvec(struct pmem_device *pmem, struct page *page,
        return rc;
 }
 
+/* account for REQ_FLUSH rename, replace with REQ_PREFLUSH after v4.8-rc1 */
+#ifndef REQ_FLUSH
+#define REQ_FLUSH REQ_PREFLUSH
+#endif
+
 static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
 {
        int rc = 0;
@@ -120,6 +126,10 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
        struct bio_vec bvec;
        struct bvec_iter iter;
        struct pmem_device *pmem = q->queuedata;
+       struct nd_region *nd_region = to_region(pmem);
+
+       if (bio->bi_rw & REQ_FLUSH)
+               nvdimm_flush(nd_region);
 
        do_acct = nd_iostat_start(bio, &start);
        bio_for_each_segment(bvec, bio, iter) {
@@ -134,8 +144,8 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
        if (do_acct)
                nd_iostat_end(bio, start);
 
-       if (bio_data_dir(bio))
-               wmb_pmem();
+       if (bio->bi_rw & REQ_FUA)
+               nvdimm_flush(nd_region);
 
        bio_endio(bio);
        return BLK_QC_T_NONE;
@@ -148,8 +158,6 @@ static int pmem_rw_page(struct block_device *bdev, sector_t sector,
        int rc;
 
        rc = pmem_do_bvec(pmem, page, PAGE_SIZE, 0, rw, sector);
-       if (rw & WRITE)
-               wmb_pmem();
 
        /*
         * The ->rw_page interface is subtle and tricky.  The core
@@ -163,8 +171,9 @@ static int pmem_rw_page(struct block_device *bdev, sector_t sector,
        return rc;
 }
 
-static long pmem_direct_access(struct block_device *bdev, sector_t sector,
-                     void __pmem **kaddr, pfn_t *pfn, long size)
+/* see "strong" declaration in tools/testing/nvdimm/pmem-dax.c */
+__weak long pmem_direct_access(struct block_device *bdev, sector_t sector,
+                     void **kaddr, pfn_t *pfn, long size)
 {
        struct pmem_device *pmem = bdev->bd_queue->queuedata;
        resource_size_t offset = sector * 512 + pmem->data_offset;
@@ -195,7 +204,7 @@ static void pmem_release_queue(void *q)
        blk_cleanup_queue(q);
 }
 
-void pmem_release_disk(void *disk)
+static void pmem_release_disk(void *disk)
 {
        del_gendisk(disk);
        put_disk(disk);
@@ -205,6 +214,7 @@ static int pmem_attach_disk(struct device *dev,
                struct nd_namespace_common *ndns)
 {
        struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
+       struct nd_region *nd_region = to_nd_region(dev->parent);
        struct vmem_altmap __altmap, *altmap = NULL;
        struct resource *res = &nsio->res;
        struct nd_pfn *nd_pfn = NULL;
@@ -234,7 +244,7 @@ static int pmem_attach_disk(struct device *dev,
        dev_set_drvdata(dev, pmem);
        pmem->phys_addr = res->start;
        pmem->size = resource_size(res);
-       if (!arch_has_wmb_pmem())
+       if (nvdimm_has_flush(nd_region) < 0)
                dev_warn(dev, "unable to guarantee persistence of writes\n");
 
        if (!devm_request_mem_region(dev, res->start, resource_size(res),
@@ -269,15 +279,14 @@ static int pmem_attach_disk(struct device *dev,
         * At release time the queue must be dead before
         * devm_memremap_pages is unwound
         */
-       if (devm_add_action(dev, pmem_release_queue, q)) {
-               blk_cleanup_queue(q);
+       if (devm_add_action_or_reset(dev, pmem_release_queue, q))
                return -ENOMEM;
-       }
 
        if (IS_ERR(addr))
                return PTR_ERR(addr);
-       pmem->virt_addr = (void __pmem *) addr;
+       pmem->virt_addr = addr;
 
+       blk_queue_write_cache(q, true, true);
        blk_queue_make_request(q, pmem_make_request);
        blk_queue_physical_block_size(q, PAGE_SIZE);
        blk_queue_max_hw_sectors(q, UINT_MAX);
@@ -289,10 +298,6 @@ static int pmem_attach_disk(struct device *dev,
        disk = alloc_disk_node(0, nid);
        if (!disk)
                return -ENOMEM;
-       if (devm_add_action(dev, pmem_release_disk, disk)) {
-               put_disk(disk);
-               return -ENOMEM;
-       }
 
        disk->fops              = &pmem_fops;
        disk->queue             = q;
@@ -302,9 +307,13 @@ static int pmem_attach_disk(struct device *dev,
                        / 512);
        if (devm_init_badblocks(dev, &pmem->bb))
                return -ENOMEM;
-       nvdimm_badblocks_populate(to_nd_region(dev->parent), &pmem->bb, res);
+       nvdimm_badblocks_populate(nd_region, &pmem->bb, res);
        disk->bb = &pmem->bb;
        device_add_disk(dev, disk);
+
+       if (devm_add_action_or_reset(dev, pmem_release_disk, disk))
+               return -ENOMEM;
+
        revalidate_disk(disk);
 
        return 0;
@@ -340,13 +349,20 @@ static int nd_pmem_remove(struct device *dev)
 {
        if (is_nd_btt(dev))
                nvdimm_namespace_detach_btt(to_nd_btt(dev));
+       nvdimm_flush(to_nd_region(dev->parent));
+
        return 0;
 }
 
+static void nd_pmem_shutdown(struct device *dev)
+{
+       nvdimm_flush(to_nd_region(dev->parent));
+}
+
 static void nd_pmem_notify(struct device *dev, enum nvdimm_event event)
 {
-       struct nd_region *nd_region = to_nd_region(dev->parent);
        struct pmem_device *pmem = dev_get_drvdata(dev);
+       struct nd_region *nd_region = to_region(pmem);
        resource_size_t offset = 0, end_trunc = 0;
        struct nd_namespace_common *ndns;
        struct nd_namespace_io *nsio;
@@ -382,6 +398,7 @@ static struct nd_device_driver nd_pmem_driver = {
        .probe = nd_pmem_probe,
        .remove = nd_pmem_remove,
        .notify = nd_pmem_notify,
+       .shutdown = nd_pmem_shutdown,
        .drv = {
                .name = "nd_pmem",
        },
diff --git a/drivers/nvdimm/pmem.h b/drivers/nvdimm/pmem.h
new file mode 100644 (file)
index 0000000..b4ee4f7
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef __NVDIMM_PMEM_H__
+#define __NVDIMM_PMEM_H__
+#include <linux/badblocks.h>
+#include <linux/types.h>
+#include <linux/pfn_t.h>
+#include <linux/fs.h>
+
+long pmem_direct_access(struct block_device *bdev, sector_t sector,
+                     void **kaddr, pfn_t *pfn, long size);
+/* this definition is in it's own header for tools/testing/nvdimm to consume */
+struct pmem_device {
+       /* One contiguous memory region per device */
+       phys_addr_t             phys_addr;
+       /* when non-zero this device is hosting a 'pfn' instance */
+       phys_addr_t             data_offset;
+       u64                     pfn_flags;
+       void                    *virt_addr;
+       /* immutable base size of the namespace */
+       size_t                  size;
+       /* trim size when namespace capacity has been section aligned */
+       u32                     pfn_pad;
+       struct badblocks        bb;
+};
+#endif /* __NVDIMM_PMEM_H__ */
index 05a9123..8f24177 100644 (file)
@@ -20,7 +20,7 @@ static int nd_region_probe(struct device *dev)
 {
        int err, rc;
        static unsigned long once;
-       struct nd_region_namespaces *num_ns;
+       struct nd_region_data *ndrd;
        struct nd_region *nd_region = to_nd_region(dev);
 
        if (nd_region->num_lanes > num_online_cpus()
@@ -33,21 +33,21 @@ static int nd_region_probe(struct device *dev)
                                nd_region->num_lanes);
        }
 
+       rc = nd_region_activate(nd_region);
+       if (rc)
+               return rc;
+
        rc = nd_blk_region_init(nd_region);
        if (rc)
                return rc;
 
        rc = nd_region_register_namespaces(nd_region, &err);
-       num_ns = devm_kzalloc(dev, sizeof(*num_ns), GFP_KERNEL);
-       if (!num_ns)
-               return -ENOMEM;
-
        if (rc < 0)
                return rc;
 
-       num_ns->active = rc;
-       num_ns->count = rc + err;
-       dev_set_drvdata(dev, num_ns);
+       ndrd = dev_get_drvdata(dev);
+       ndrd->ns_active = rc;
+       ndrd->ns_count = rc + err;
 
        if (rc && err && rc == err)
                return -ENODEV;
@@ -82,6 +82,8 @@ static int nd_region_remove(struct device *dev)
 {
        struct nd_region *nd_region = to_nd_region(dev);
 
+       device_for_each_child(dev, NULL, child_unregister);
+
        /* flush attribute readers and disable */
        nvdimm_bus_lock(dev);
        nd_region->ns_seed = NULL;
@@ -91,7 +93,6 @@ static int nd_region_remove(struct device *dev)
        dev_set_drvdata(dev, NULL);
        nvdimm_bus_unlock(dev);
 
-       device_for_each_child(dev, NULL, child_unregister);
        return 0;
 }
 
index 40fcfea..e8d5ba7 100644 (file)
 #include <linux/highmem.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/hash.h>
+#include <linux/pmem.h>
 #include <linux/sort.h>
 #include <linux/io.h>
 #include <linux/nd.h>
 #include "nd-core.h"
 #include "nd.h"
 
+/*
+ * For readq() and writeq() on 32-bit builds, the hi-lo, lo-hi order is
+ * irrelevant.
+ */
+#include <linux/io-64-nonatomic-hi-lo.h>
+
 static DEFINE_IDA(region_ida);
+static DEFINE_PER_CPU(int, flush_idx);
+
+static int nvdimm_map_flush(struct device *dev, struct nvdimm *nvdimm, int dimm,
+               struct nd_region_data *ndrd)
+{
+       int i, j;
+
+       dev_dbg(dev, "%s: map %d flush address%s\n", nvdimm_name(nvdimm),
+                       nvdimm->num_flush, nvdimm->num_flush == 1 ? "" : "es");
+       for (i = 0; i < nvdimm->num_flush; i++) {
+               struct resource *res = &nvdimm->flush_wpq[i];
+               unsigned long pfn = PHYS_PFN(res->start);
+               void __iomem *flush_page;
+
+               /* check if flush hints share a page */
+               for (j = 0; j < i; j++) {
+                       struct resource *res_j = &nvdimm->flush_wpq[j];
+                       unsigned long pfn_j = PHYS_PFN(res_j->start);
+
+                       if (pfn == pfn_j)
+                               break;
+               }
+
+               if (j < i)
+                       flush_page = (void __iomem *) ((unsigned long)
+                                       ndrd->flush_wpq[dimm][j] & PAGE_MASK);
+               else
+                       flush_page = devm_nvdimm_ioremap(dev,
+                                       PHYS_PFN(pfn), PAGE_SIZE);
+               if (!flush_page)
+                       return -ENXIO;
+               ndrd->flush_wpq[dimm][i] = flush_page
+                       + (res->start & ~PAGE_MASK);
+       }
+
+       return 0;
+}
+
+int nd_region_activate(struct nd_region *nd_region)
+{
+       int i, num_flush = 0;
+       struct nd_region_data *ndrd;
+       struct device *dev = &nd_region->dev;
+       size_t flush_data_size = sizeof(void *);
+
+       nvdimm_bus_lock(&nd_region->dev);
+       for (i = 0; i < nd_region->ndr_mappings; i++) {
+               struct nd_mapping *nd_mapping = &nd_region->mapping[i];
+               struct nvdimm *nvdimm = nd_mapping->nvdimm;
+
+               /* at least one null hint slot per-dimm for the "no-hint" case */
+               flush_data_size += sizeof(void *);
+               num_flush = min_not_zero(num_flush, nvdimm->num_flush);
+               if (!nvdimm->num_flush)
+                       continue;
+               flush_data_size += nvdimm->num_flush * sizeof(void *);
+       }
+       nvdimm_bus_unlock(&nd_region->dev);
+
+       ndrd = devm_kzalloc(dev, sizeof(*ndrd) + flush_data_size, GFP_KERNEL);
+       if (!ndrd)
+               return -ENOMEM;
+       dev_set_drvdata(dev, ndrd);
+
+       ndrd->flush_mask = (1 << ilog2(num_flush)) - 1;
+       for (i = 0; i < nd_region->ndr_mappings; i++) {
+               struct nd_mapping *nd_mapping = &nd_region->mapping[i];
+               struct nvdimm *nvdimm = nd_mapping->nvdimm;
+               int rc = nvdimm_map_flush(&nd_region->dev, nvdimm, i, ndrd);
+
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
 
 static void nd_region_release(struct device *dev)
 {
@@ -242,12 +326,12 @@ static DEVICE_ATTR_RO(available_size);
 static ssize_t init_namespaces_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct nd_region_namespaces *num_ns = dev_get_drvdata(dev);
+       struct nd_region_data *ndrd = dev_get_drvdata(dev);
        ssize_t rc;
 
        nvdimm_bus_lock(dev);
-       if (num_ns)
-               rc = sprintf(buf, "%d/%d\n", num_ns->active, num_ns->count);
+       if (ndrd)
+               rc = sprintf(buf, "%d/%d\n", ndrd->ns_active, ndrd->ns_count);
        else
                rc = -ENXIO;
        nvdimm_bus_unlock(dev);
@@ -433,8 +517,6 @@ static void nd_region_notify_driver_action(struct nvdimm_bus *nvdimm_bus,
 
                if (is_nd_pmem(dev))
                        return;
-
-               to_nd_blk_region(dev)->disable(nvdimm_bus, dev);
        }
        if (dev->parent && is_nd_blk(dev->parent) && probe) {
                nd_region = to_nd_region(dev->parent);
@@ -698,7 +780,6 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
                if (ndbr) {
                        nd_region = &ndbr->nd_region;
                        ndbr->enable = ndbr_desc->enable;
-                       ndbr->disable = ndbr_desc->disable;
                        ndbr->do_io = ndbr_desc->do_io;
                }
                region_buf = ndbr;
@@ -794,6 +875,67 @@ struct nd_region *nvdimm_volatile_region_create(struct nvdimm_bus *nvdimm_bus,
 }
 EXPORT_SYMBOL_GPL(nvdimm_volatile_region_create);
 
+/**
+ * nvdimm_flush - flush any posted write queues between the cpu and pmem media
+ * @nd_region: blk or interleaved pmem region
+ */
+void nvdimm_flush(struct nd_region *nd_region)
+{
+       struct nd_region_data *ndrd = dev_get_drvdata(&nd_region->dev);
+       int i, idx;
+
+       /*
+        * Try to encourage some diversity in flush hint addresses
+        * across cpus assuming a limited number of flush hints.
+        */
+       idx = this_cpu_read(flush_idx);
+       idx = this_cpu_add_return(flush_idx, hash_32(current->pid + idx, 8));
+
+       /*
+        * The first wmb() is needed to 'sfence' all previous writes
+        * such that they are architecturally visible for the platform
+        * buffer flush.  Note that we've already arranged for pmem
+        * writes to avoid the cache via arch_memcpy_to_pmem().  The
+        * final wmb() ensures ordering for the NVDIMM flush write.
+        */
+       wmb();
+       for (i = 0; i < nd_region->ndr_mappings; i++)
+               if (ndrd->flush_wpq[i][0])
+                       writeq(1, ndrd->flush_wpq[i][idx & ndrd->flush_mask]);
+       wmb();
+}
+EXPORT_SYMBOL_GPL(nvdimm_flush);
+
+/**
+ * nvdimm_has_flush - determine write flushing requirements
+ * @nd_region: blk or interleaved pmem region
+ *
+ * Returns 1 if writes require flushing
+ * Returns 0 if writes do not require flushing
+ * Returns -ENXIO if flushing capability can not be determined
+ */
+int nvdimm_has_flush(struct nd_region *nd_region)
+{
+       struct nd_region_data *ndrd = dev_get_drvdata(&nd_region->dev);
+       int i;
+
+       /* no nvdimm == flushing capability unknown */
+       if (nd_region->ndr_mappings == 0)
+               return -ENXIO;
+
+       for (i = 0; i < nd_region->ndr_mappings; i++)
+               /* flush hints present, flushing required */
+               if (ndrd->flush_wpq[i][0])
+                       return 1;
+
+       /*
+        * The platform defines dimm devices without hints, assume
+        * platform persistence mechanism like ADR
+        */
+       return 0;
+}
+EXPORT_SYMBOL_GPL(nvdimm_has_flush);
+
 void __exit nd_region_devs_exit(void)
 {
        ida_destroy(&region_ida);
index fb8200b..b3fe1d3 100644 (file)
@@ -35,7 +35,7 @@ config PINCTRL_ADI2
          machine and arch are selected to build.
 
 config PINCTRL_AS3722
-       bool "Pinctrl and GPIO driver for ams AS3722 PMIC"
+       tristate "Pinctrl and GPIO driver for ams AS3722 PMIC"
        depends on MFD_AS3722 && GPIOLIB
        select PINMUX
        select GENERIC_PINCONF
@@ -129,6 +129,17 @@ config PINCTRL_MESON
        select OF_GPIO
        select REGMAP_MMIO
 
+config PINCTRL_OXNAS
+       bool
+       depends on OF
+       select PINMUX
+       select PINCONF
+       select GENERIC_PINCONF
+       select GPIOLIB
+       select OF_GPIO
+       select GPIOLIB_IRQCHIP
+       select MFD_SYSCON
+
 config PINCTRL_ROCKCHIP
        bool
        select PINMUX
@@ -196,8 +207,19 @@ config PINCTRL_COH901
          COH 901 335 and COH 901 571/3. They contain 3, 5 or 7
          ports of 8 GPIO pins each.
 
+config PINCTRL_MAX77620
+       tristate "MAX77620/MAX20024 Pincontrol support"
+       depends on MFD_MAX77620
+       select PINMUX
+       select GENERIC_PINCONF
+       help
+         Say Yes here to enable Pin control support for Maxim PMIC MAX77620.
+         This PMIC has 8 GPIO pins that work as GPIO as well as special
+         function in alternate mode. This driver also configure push-pull,
+         open drain, FPS slots etc.
+
 config PINCTRL_PALMAS
-       bool "Pinctrl driver for the PALMAS Series MFD devices"
+       tristate "Pinctrl driver for the PALMAS Series MFD devices"
        depends on OF && MFD_PALMAS
        select PINMUX
        select GENERIC_PINCONF
index 42a5c1d..8ebd7b8 100644 (file)
@@ -16,7 +16,9 @@ obj-$(CONFIG_PINCTRL_AT91PIO4)        += pinctrl-at91-pio4.o
 obj-$(CONFIG_PINCTRL_AMD)      += pinctrl-amd.o
 obj-$(CONFIG_PINCTRL_DIGICOLOR)        += pinctrl-digicolor.o
 obj-$(CONFIG_PINCTRL_FALCON)   += pinctrl-falcon.o
+obj-$(CONFIG_PINCTRL_MAX77620) += pinctrl-max77620.o
 obj-$(CONFIG_PINCTRL_MESON)    += meson/
+obj-$(CONFIG_PINCTRL_OXNAS)    += pinctrl-oxnas.o
 obj-$(CONFIG_PINCTRL_PALMAS)   += pinctrl-palmas.o
 obj-$(CONFIG_PINCTRL_PIC32)    += pinctrl-pic32.o
 obj-$(CONFIG_PINCTRL_PISTACHIO)        += pinctrl-pistachio.o
@@ -35,7 +37,7 @@ obj-$(CONFIG_PINCTRL_TB10X)   += pinctrl-tb10x.o
 obj-$(CONFIG_PINCTRL_ST)       += pinctrl-st.o
 obj-$(CONFIG_PINCTRL_ZYNQ)     += pinctrl-zynq.o
 
-obj-$(CONFIG_ARCH_BCM)         += bcm/
+obj-y                          += bcm/
 obj-$(CONFIG_PINCTRL_BERLIN)   += berlin/
 obj-y                          += freescale/
 obj-$(CONFIG_X86)              += intel/
index c356223..6324677 100644 (file)
@@ -60,6 +60,7 @@ config PINCTRL_IPROC_GPIO
 config PINCTRL_CYGNUS_MUX
        bool "Broadcom Cygnus IOMUX driver"
        depends on (ARCH_BCM_CYGNUS || COMPILE_TEST)
+       depends on OF
        select PINMUX
        select GENERIC_PINCONF
        default ARCH_BCM_CYGNUS
@@ -99,3 +100,17 @@ config PINCTRL_NS2_MUX
 
          The Broadcom Northstar2 IOMUX driver supports group based IOMUX
          configuration.
+
+config PINCTRL_NSP_MUX
+       bool "Broadcom NSP IOMUX driver"
+       depends on (ARCH_BCM_NSP || COMPILE_TEST)
+       depends on OF
+       select PINMUX
+       select GENERIC_PINCONF
+       default ARCH_BCM_NSP
+       help
+         Say yes here to enable the Broadcom NSP SOC IOMUX driver.
+
+         The Broadcom Northstar Plus IOMUX driver supports pin based IOMUX
+         configuration, with certain individual pins can be overridden
+         to GPIO function.
index 3861a1c..2a65111 100644 (file)
@@ -6,3 +6,4 @@ obj-$(CONFIG_PINCTRL_IPROC_GPIO)        += pinctrl-iproc-gpio.o
 obj-$(CONFIG_PINCTRL_CYGNUS_MUX)       += pinctrl-cygnus-mux.o
 obj-$(CONFIG_PINCTRL_NSP_GPIO)         += pinctrl-nsp-gpio.o
 obj-$(CONFIG_PINCTRL_NS2_MUX)          += pinctrl-ns2-mux.o
+obj-$(CONFIG_PINCTRL_NSP_MUX)          += pinctrl-nsp-mux.o
index 3670f5e..7f77007 100644 (file)
 #define GPIO_DRV_STRENGTH_BITS       3
 #define GPIO_DRV_STRENGTH_BIT_MASK   ((1 << GPIO_DRV_STRENGTH_BITS) - 1)
 
+enum iproc_pinconf_param {
+       IPROC_PINCONF_DRIVE_STRENGTH = 0,
+       IPROC_PINCONF_BIAS_DISABLE,
+       IPROC_PINCONF_BIAS_PULL_UP,
+       IPROC_PINCONF_BIAS_PULL_DOWN,
+       IPROC_PINCON_MAX,
+};
+
 /*
  * Iproc GPIO core
  *
  * @num_banks: number of GPIO banks, each bank supports up to 32 GPIOs
  * @pinmux_is_supported: flag to indicate this GPIO controller contains pins
  * that can be individually muxed to GPIO
+ * @pinconf_disable: contains a list of PINCONF parameters that need to be
+ * disabled
+ * @nr_pinconf_disable: total number of PINCONF parameters that need to be
+ * disabled
  * @pctl: pointer to pinctrl_dev
  * @pctldesc: pinctrl descriptor
  */
@@ -94,6 +106,9 @@ struct iproc_gpio {
 
        bool pinmux_is_supported;
 
+       enum pin_config_param *pinconf_disable;
+       unsigned int nr_pinconf_disable;
+
        struct pinctrl_dev *pctl;
        struct pinctrl_desc pctldesc;
 };
@@ -360,6 +375,65 @@ static int iproc_gpio_get(struct gpio_chip *gc, unsigned gpio)
        return !!(readl(chip->base + offset) & BIT(shift));
 }
 
+/*
+ * Mapping of the iProc PINCONF parameters to the generic pin configuration
+ * parameters
+ */
+static const enum pin_config_param iproc_pinconf_disable_map[] = {
+       [IPROC_PINCONF_DRIVE_STRENGTH] = PIN_CONFIG_DRIVE_STRENGTH,
+       [IPROC_PINCONF_BIAS_DISABLE] = PIN_CONFIG_BIAS_DISABLE,
+       [IPROC_PINCONF_BIAS_PULL_UP] = PIN_CONFIG_BIAS_PULL_UP,
+       [IPROC_PINCONF_BIAS_PULL_DOWN] = PIN_CONFIG_BIAS_PULL_DOWN,
+};
+
+static bool iproc_pinconf_param_is_disabled(struct iproc_gpio *chip,
+                                           enum pin_config_param param)
+{
+       unsigned int i;
+
+       if (!chip->nr_pinconf_disable)
+               return false;
+
+       for (i = 0; i < chip->nr_pinconf_disable; i++)
+               if (chip->pinconf_disable[i] == param)
+                       return true;
+
+       return false;
+}
+
+static int iproc_pinconf_disable_map_create(struct iproc_gpio *chip,
+                                           unsigned long disable_mask)
+{
+       unsigned int map_size = ARRAY_SIZE(iproc_pinconf_disable_map);
+       unsigned int bit, nbits = 0;
+
+       /* figure out total number of PINCONF parameters to disable */
+       for_each_set_bit(bit, &disable_mask, map_size)
+               nbits++;
+
+       if (!nbits)
+               return 0;
+
+       /*
+        * Allocate an array to store PINCONF parameters that need to be
+        * disabled
+        */
+       chip->pinconf_disable = devm_kcalloc(chip->dev, nbits,
+                                            sizeof(*chip->pinconf_disable),
+                                            GFP_KERNEL);
+       if (!chip->pinconf_disable)
+               return -ENOMEM;
+
+       chip->nr_pinconf_disable = nbits;
+
+       /* now store these parameters */
+       nbits = 0;
+       for_each_set_bit(bit, &disable_mask, map_size)
+               chip->pinconf_disable[nbits++] = iproc_pinconf_disable_map[bit];
+
+       return 0;
+}
+
 static int iproc_get_groups_count(struct pinctrl_dev *pctldev)
 {
        return 1;
@@ -500,6 +574,9 @@ static int iproc_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
        bool disable, pull_up;
        int ret;
 
+       if (iproc_pinconf_param_is_disabled(chip, param))
+               return -ENOTSUPP;
+
        switch (param) {
        case PIN_CONFIG_BIAS_DISABLE:
                iproc_gpio_get_pull(chip, gpio, &disable, &pull_up);
@@ -548,6 +625,10 @@ static int iproc_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
 
        for (i = 0; i < num_configs; i++) {
                param = pinconf_to_config_param(configs[i]);
+
+               if (iproc_pinconf_param_is_disabled(chip, param))
+                       return -ENOTSUPP;
+
                arg = pinconf_to_config_argument(configs[i]);
 
                switch (param) {
@@ -633,11 +714,13 @@ static int iproc_gpio_register_pinconf(struct iproc_gpio *chip)
 }
 
 static const struct of_device_id iproc_gpio_of_match[] = {
+       { .compatible = "brcm,iproc-gpio" },
        { .compatible = "brcm,cygnus-ccm-gpio" },
        { .compatible = "brcm,cygnus-asiu-gpio" },
        { .compatible = "brcm,cygnus-crmu-gpio" },
-       { .compatible = "brcm,iproc-gpio" },
-       { }
+       { .compatible = "brcm,iproc-nsp-gpio" },
+       { .compatible = "brcm,iproc-stingray-gpio" },
+       { /* sentinel */ }
 };
 
 static int iproc_gpio_probe(struct platform_device *pdev)
@@ -646,8 +729,17 @@ static int iproc_gpio_probe(struct platform_device *pdev)
        struct resource *res;
        struct iproc_gpio *chip;
        struct gpio_chip *gc;
-       u32 ngpios;
+       u32 ngpios, pinconf_disable_mask = 0;
        int irq, ret;
+       bool no_pinconf = false;
+
+       /* NSP does not support drive strength config */
+       if (of_device_is_compatible(dev->of_node, "brcm,iproc-nsp-gpio"))
+               pinconf_disable_mask = BIT(IPROC_PINCONF_DRIVE_STRENGTH);
+       /* Stingray does not support pinconf in this controller */
+       else if (of_device_is_compatible(dev->of_node,
+                                        "brcm,iproc-stingray-gpio"))
+               no_pinconf = true;
 
        chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
@@ -702,10 +794,22 @@ static int iproc_gpio_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = iproc_gpio_register_pinconf(chip);
-       if (ret) {
-               dev_err(dev, "unable to register pinconf\n");
-               goto err_rm_gpiochip;
+       if (!no_pinconf) {
+               ret = iproc_gpio_register_pinconf(chip);
+               if (ret) {
+                       dev_err(dev, "unable to register pinconf\n");
+                       goto err_rm_gpiochip;
+               }
+
+               if (pinconf_disable_mask) {
+                       ret = iproc_pinconf_disable_map_create(chip,
+                                                        pinconf_disable_mask);
+                       if (ret) {
+                               dev_err(dev,
+                                       "unable to create pinconf disable map\n");
+                               goto err_rm_gpiochip;
+                       }
+               }
        }
 
        /* optional GPIO interrupt support */
index 3fefd14..ca81789 100644 (file)
@@ -1044,10 +1044,8 @@ static int ns2_pinmux_probe(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        pinctrl->base0 = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(pinctrl->base0)) {
-               dev_err(&pdev->dev, "unable to map I/O space\n");
+       if (IS_ERR(pinctrl->base0))
                return PTR_ERR(pinctrl->base0);
-       }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        pinctrl->base1 = devm_ioremap_nocache(&pdev->dev, res->start,
@@ -1059,10 +1057,8 @@ static int ns2_pinmux_probe(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
        pinctrl->pinconf_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(pinctrl->pinconf_base)) {
-               dev_err(&pdev->dev, "unable to map I/O space\n");
+       if (IS_ERR(pinctrl->pinconf_base))
                return PTR_ERR(pinctrl->pinconf_base);
-       }
 
        ret = ns2_mux_log_init(pinctrl);
        if (ret) {
@@ -1089,9 +1085,9 @@ static int ns2_pinmux_probe(struct platform_device *pdev)
 
        pinctrl->pctl = pinctrl_register(&ns2_pinctrl_desc, &pdev->dev,
                        pinctrl);
-       if (!pinctrl->pctl) {
+       if (IS_ERR(pinctrl->pctl)) {
                dev_err(&pdev->dev, "unable to register IOMUX pinctrl\n");
-               return -EINVAL;
+               return PTR_ERR(pinctrl->pctl);
        }
 
        return 0;
index a8b37a9..35783db 100644 (file)
@@ -458,13 +458,15 @@ static int nsp_gpio_get_strength(struct nsp_gpio *chip, unsigned gpio,
        return 0;
 }
 
-int nsp_pin_config_group_get(struct pinctrl_dev *pctldev, unsigned selector,
+static int nsp_pin_config_group_get(struct pinctrl_dev *pctldev,
+                                   unsigned selector,
                             unsigned long *config)
 {
        return 0;
 }
 
-int nsp_pin_config_group_set(struct pinctrl_dev *pctldev, unsigned selector,
+static int nsp_pin_config_group_set(struct pinctrl_dev *pctldev,
+                                   unsigned selector,
                             unsigned long *configs, unsigned num_configs)
 {
        return 0;
diff --git a/drivers/pinctrl/bcm/pinctrl-nsp-mux.c b/drivers/pinctrl/bcm/pinctrl-nsp-mux.c
new file mode 100644 (file)
index 0000000..4149db3
--- /dev/null
@@ -0,0 +1,642 @@
+/* Copyright (C) 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * This file contains the Northstar plus (NSP) IOMUX driver that supports
+ * group based PINMUX configuration. The Northstar plus IOMUX controller
+ * allows pins to be individually muxed to GPIO function. The NAND and MMC is
+ * a group based selection. The gpio_a 8 - 11 are muxed with gpio_b and pwm.
+ * To select PWM, one need to enable the corresponding gpio_b as well.
+ *
+ *                             gpio_a (8 - 11)
+ *                             +----------
+ *                             |
+ *             gpio_a (8-11)   |       gpio_b (0 - 3)
+ *     ------------------------+-------+----------
+ *                                     |
+ *                                     |       pwm (0 - 3)
+ *                                     +----------
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "../core.h"
+#include "../pinctrl-utils.h"
+
+#define NSP_MUX_BASE0  0x00
+#define NSP_MUX_BASE1  0x01
+#define NSP_MUX_BASE2  0x02
+/*
+ * nsp IOMUX register description
+ *
+ * @base: base 0 or base 1
+ * @shift: bit shift for mux configuration of a group
+ * @mask: bit mask of the function
+ * @alt: alternate function to set to
+ */
+struct nsp_mux {
+       unsigned int base;
+       unsigned int shift;
+       unsigned int mask;
+       unsigned int alt;
+};
+
+/*
+ * Keep track of nsp IOMUX configuration and prevent double configuration
+ *
+ * @nsp_mux: nsp IOMUX register description
+ * @is_configured: flag to indicate whether a mux setting has already been
+ * configured
+ */
+struct nsp_mux_log {
+       struct nsp_mux mux;
+       bool is_configured;
+};
+
+/*
+ * Group based IOMUX configuration
+ *
+ * @name: name of the group
+ * @pins: array of pins used by this group
+ * @num_pins: total number of pins used by this group
+ * @mux: nsp group based IOMUX configuration
+ */
+struct nsp_pin_group {
+       const char *name;
+       const unsigned int *pins;
+       const unsigned int num_pins;
+       const struct nsp_mux mux;
+};
+
+/*
+ * nsp mux function and supported pin groups
+ *
+ * @name: name of the function
+ * @groups: array of groups that can be supported by this function
+ * @num_groups: total number of groups that can be supported by this function
+ */
+struct nsp_pin_function {
+       const char *name;
+       const char * const *groups;
+       const unsigned int num_groups;
+};
+
+/*
+ * nsp IOMUX pinctrl core
+ *
+ * @pctl: pointer to pinctrl_dev
+ * @dev: pointer to device
+ * @base0: first mux register
+ * @base1: second mux register
+ * @base2: third mux register
+ * @groups: pointer to array of groups
+ * @num_groups: total number of groups
+ * @functions: pointer to array of functions
+ * @num_functions: total number of functions
+ * @mux_log: pointer to the array of mux logs
+ * @lock: lock to protect register access
+ */
+struct nsp_pinctrl {
+       struct pinctrl_dev *pctl;
+       struct device *dev;
+       void __iomem *base0;
+       void __iomem *base1;
+       void __iomem *base2;
+       const struct nsp_pin_group *groups;
+       unsigned int num_groups;
+       const struct nsp_pin_function *functions;
+       unsigned int num_functions;
+       struct nsp_mux_log *mux_log;
+       spinlock_t lock;
+};
+
+/*
+ * Description of a pin in nsp
+ *
+ * @pin: pin number
+ * @name: pin name
+ * @gpio_select: reg data to select GPIO
+ */
+struct nsp_pin {
+       unsigned int pin;
+       char *name;
+       unsigned int gpio_select;
+};
+
+#define NSP_PIN_DESC(p, n, g)          \
+{                                      \
+       .pin = p,                       \
+       .name = n,                      \
+       .gpio_select = g,               \
+}
+
+/*
+ * List of muxable pins in nsp
+ */
+static struct nsp_pin nsp_pins[] = {
+       NSP_PIN_DESC(0, "spi_clk", 1),
+       NSP_PIN_DESC(1, "spi_ss", 1),
+       NSP_PIN_DESC(2, "spi_mosi", 1),
+       NSP_PIN_DESC(3, "spi_miso", 1),
+       NSP_PIN_DESC(4, "scl", 1),
+       NSP_PIN_DESC(5, "sda", 1),
+       NSP_PIN_DESC(6, "mdc", 1),
+       NSP_PIN_DESC(7, "mdio", 1),
+       NSP_PIN_DESC(8, "pwm0", 1),
+       NSP_PIN_DESC(9, "pwm1", 1),
+       NSP_PIN_DESC(10, "pwm2", 1),
+       NSP_PIN_DESC(11, "pwm3", 1),
+       NSP_PIN_DESC(12, "uart1_rx", 1),
+       NSP_PIN_DESC(13, "uart1_tx", 1),
+       NSP_PIN_DESC(14, "uart1_cts", 1),
+       NSP_PIN_DESC(15, "uart1_rts", 1),
+       NSP_PIN_DESC(16, "uart2_rx", 1),
+       NSP_PIN_DESC(17, "uart2_tx", 1),
+       NSP_PIN_DESC(18, "synce", 0),
+       NSP_PIN_DESC(19, "sata0_led", 0),
+       NSP_PIN_DESC(20, "sata1_led", 0),
+       NSP_PIN_DESC(21, "xtal_out", 1),
+       NSP_PIN_DESC(22, "sdio_pwr", 1),
+       NSP_PIN_DESC(23, "sdio_en_1p8v", 1),
+       NSP_PIN_DESC(24, "gpio_24", 1),
+       NSP_PIN_DESC(25, "gpio_25", 1),
+       NSP_PIN_DESC(26, "p5_led0", 0),
+       NSP_PIN_DESC(27, "p5_led1", 0),
+       NSP_PIN_DESC(28, "gpio_28", 1),
+       NSP_PIN_DESC(29, "gpio_29", 1),
+       NSP_PIN_DESC(30, "gpio_30", 1),
+       NSP_PIN_DESC(31, "gpio_31", 1),
+       NSP_PIN_DESC(32, "nand_ale", 0),
+       NSP_PIN_DESC(33, "nand_ce0", 0),
+       NSP_PIN_DESC(34, "nand_r/b", 0),
+       NSP_PIN_DESC(35, "nand_dq0", 0),
+       NSP_PIN_DESC(36, "nand_dq1", 0),
+       NSP_PIN_DESC(37, "nand_dq2", 0),
+       NSP_PIN_DESC(38, "nand_dq3", 0),
+       NSP_PIN_DESC(39, "nand_dq4", 0),
+       NSP_PIN_DESC(40, "nand_dq5", 0),
+       NSP_PIN_DESC(41, "nand_dq6", 0),
+       NSP_PIN_DESC(42, "nand_dq7", 0),
+};
+
+/*
+ * List of groups of pins
+ */
+
+static const unsigned int spi_pins[] = {0, 1, 2, 3};
+static const unsigned int i2c_pins[] = {4, 5};
+static const unsigned int mdio_pins[] = {6, 7};
+static const unsigned int pwm0_pins[] = {8};
+static const unsigned int gpio_b_0_pins[] = {8};
+static const unsigned int pwm1_pins[] = {9};
+static const unsigned int gpio_b_1_pins[] = {9};
+static const unsigned int pwm2_pins[] = {10};
+static const unsigned int gpio_b_2_pins[] = {10};
+static const unsigned int pwm3_pins[] = {11};
+static const unsigned int gpio_b_3_pins[] = {11};
+static const unsigned int uart1_pins[] = {12, 13, 14, 15};
+static const unsigned int uart2_pins[] = {16, 17};
+static const unsigned int synce_pins[] = {18};
+static const unsigned int sata0_led_pins[] = {19};
+static const unsigned int sata1_led_pins[] = {20};
+static const unsigned int xtal_out_pins[] = {21};
+static const unsigned int sdio_pwr_pins[] = {22};
+static const unsigned int sdio_1p8v_pins[] = {23};
+static const unsigned int switch_p05_led0_pins[] = {26};
+static const unsigned int switch_p05_led1_pins[] = {27};
+static const unsigned int nand_pins[] = {32, 33, 34, 35, 36, 37, 38, 39,
+                                                       40, 41, 42};
+static const unsigned int emmc_pins[] = {32, 33, 34, 35, 36, 37, 38, 39,
+                                                       40, 41, 42};
+
+#define NSP_PIN_GROUP(group_name, ba, sh, ma, al)      \
+{                                                      \
+       .name = __stringify(group_name) "_grp",         \
+       .pins = group_name ## _pins,                    \
+       .num_pins = ARRAY_SIZE(group_name ## _pins),    \
+       .mux = {                                        \
+               .base = ba,                             \
+               .shift = sh,                            \
+               .mask = ma,                             \
+               .alt = al,                              \
+       }                                               \
+}
+
+/*
+ * List of nsp pin groups
+ */
+static const struct nsp_pin_group nsp_pin_groups[] = {
+       NSP_PIN_GROUP(spi, NSP_MUX_BASE0, 0, 0x0f, 0x00),
+       NSP_PIN_GROUP(i2c, NSP_MUX_BASE0, 3, 0x03, 0x00),
+       NSP_PIN_GROUP(mdio, NSP_MUX_BASE0, 5, 0x03, 0x00),
+       NSP_PIN_GROUP(gpio_b_0, NSP_MUX_BASE0, 7, 0x01, 0x00),
+       NSP_PIN_GROUP(pwm0, NSP_MUX_BASE1, 0, 0x01, 0x01),
+       NSP_PIN_GROUP(gpio_b_1, NSP_MUX_BASE0, 8, 0x01, 0x00),
+       NSP_PIN_GROUP(pwm1, NSP_MUX_BASE1, 1, 0x01, 0x01),
+       NSP_PIN_GROUP(gpio_b_2, NSP_MUX_BASE0, 9, 0x01, 0x00),
+       NSP_PIN_GROUP(pwm2, NSP_MUX_BASE1, 2, 0x01, 0x01),
+       NSP_PIN_GROUP(gpio_b_3, NSP_MUX_BASE0, 10, 0x01, 0x00),
+       NSP_PIN_GROUP(pwm3, NSP_MUX_BASE1, 3, 0x01, 0x01),
+       NSP_PIN_GROUP(uart1, NSP_MUX_BASE0, 11, 0x0f, 0x00),
+       NSP_PIN_GROUP(uart2, NSP_MUX_BASE0, 15, 0x03, 0x00),
+       NSP_PIN_GROUP(synce, NSP_MUX_BASE0, 17, 0x01, 0x01),
+       NSP_PIN_GROUP(sata0_led, NSP_MUX_BASE0, 18, 0x01, 0x01),
+       NSP_PIN_GROUP(sata1_led, NSP_MUX_BASE0, 19, 0x01, 0x01),
+       NSP_PIN_GROUP(xtal_out, NSP_MUX_BASE0, 20, 0x01, 0x00),
+       NSP_PIN_GROUP(sdio_pwr, NSP_MUX_BASE0, 21, 0x01, 0x00),
+       NSP_PIN_GROUP(sdio_1p8v, NSP_MUX_BASE0, 22, 0x01, 0x00),
+       NSP_PIN_GROUP(switch_p05_led0, NSP_MUX_BASE0, 26, 0x01, 0x01),
+       NSP_PIN_GROUP(switch_p05_led1, NSP_MUX_BASE0, 27, 0x01, 0x01),
+       NSP_PIN_GROUP(nand, NSP_MUX_BASE2, 0, 0x01, 0x00),
+       NSP_PIN_GROUP(emmc, NSP_MUX_BASE2, 0, 0x01, 0x01)
+};
+
+/*
+ * List of groups supported by functions
+ */
+
+static const char * const spi_grps[] = {"spi_grp"};
+static const char * const i2c_grps[] = {"i2c_grp"};
+static const char * const mdio_grps[] = {"mdio_grp"};
+static const char * const pwm_grps[] = {"pwm0_grp", "pwm1_grp", "pwm2_grp"
+                                               , "pwm3_grp"};
+static const char * const gpio_b_grps[] = {"gpio_b_0_grp", "gpio_b_1_grp",
+                                       "gpio_b_2_grp", "gpio_b_3_grp"};
+static const char * const uart1_grps[] = {"uart1_grp"};
+static const char * const uart2_grps[] = {"uart2_grp"};
+static const char * const synce_grps[] = {"synce_grp"};
+static const char * const sata_led_grps[] = {"sata0_led_grp", "sata1_led_grp"};
+static const char * const xtal_out_grps[] = {"xtal_out_grp"};
+static const char * const sdio_grps[] = {"sdio_pwr_grp", "sdio_1p8v_grp"};
+static const char * const switch_led_grps[] = {"switch_p05_led0_grp",
+                                               "switch_p05_led1_grp"};
+static const char * const nand_grps[] = {"nand_grp"};
+static const char * const emmc_grps[] = {"emmc_grp"};
+
+#define NSP_PIN_FUNCTION(func)                         \
+{                                                      \
+       .name = #func,                                  \
+       .groups = func ## _grps,                        \
+       .num_groups = ARRAY_SIZE(func ## _grps),        \
+}
+
+/*
+ * List of supported functions in nsp
+ */
+static const struct nsp_pin_function nsp_pin_functions[] = {
+       NSP_PIN_FUNCTION(spi),
+       NSP_PIN_FUNCTION(i2c),
+       NSP_PIN_FUNCTION(mdio),
+       NSP_PIN_FUNCTION(pwm),
+       NSP_PIN_FUNCTION(gpio_b),
+       NSP_PIN_FUNCTION(uart1),
+       NSP_PIN_FUNCTION(uart2),
+       NSP_PIN_FUNCTION(synce),
+       NSP_PIN_FUNCTION(sata_led),
+       NSP_PIN_FUNCTION(xtal_out),
+       NSP_PIN_FUNCTION(sdio),
+       NSP_PIN_FUNCTION(switch_led),
+       NSP_PIN_FUNCTION(nand),
+       NSP_PIN_FUNCTION(emmc)
+};
+
+static int nsp_get_groups_count(struct pinctrl_dev *pctrl_dev)
+{
+       struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+       return pinctrl->num_groups;
+}
+
+static const char *nsp_get_group_name(struct pinctrl_dev *pctrl_dev,
+                                     unsigned int selector)
+{
+       struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+       return pinctrl->groups[selector].name;
+}
+
+static int nsp_get_group_pins(struct pinctrl_dev *pctrl_dev,
+                             unsigned int selector, const unsigned int **pins,
+                             unsigned int *num_pins)
+{
+       struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+       *pins = pinctrl->groups[selector].pins;
+       *num_pins = pinctrl->groups[selector].num_pins;
+
+       return 0;
+}
+
+static void nsp_pin_dbg_show(struct pinctrl_dev *pctrl_dev,
+                            struct seq_file *s, unsigned int offset)
+{
+       seq_printf(s, " %s", dev_name(pctrl_dev->dev));
+}
+
+static struct pinctrl_ops nsp_pinctrl_ops = {
+       .get_groups_count = nsp_get_groups_count,
+       .get_group_name = nsp_get_group_name,
+       .get_group_pins = nsp_get_group_pins,
+       .pin_dbg_show = nsp_pin_dbg_show,
+       .dt_node_to_map = pinconf_generic_dt_node_to_map_group,
+       .dt_free_map = pinctrl_utils_free_map,
+};
+
+static int nsp_get_functions_count(struct pinctrl_dev *pctrl_dev)
+{
+       struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+       return pinctrl->num_functions;
+}
+
+static const char *nsp_get_function_name(struct pinctrl_dev *pctrl_dev,
+                                        unsigned int selector)
+{
+       struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+       return pinctrl->functions[selector].name;
+}
+
+static int nsp_get_function_groups(struct pinctrl_dev *pctrl_dev,
+                                  unsigned int selector,
+                                  const char * const **groups,
+                                  unsigned * const num_groups)
+{
+       struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+       *groups = pinctrl->functions[selector].groups;
+       *num_groups = pinctrl->functions[selector].num_groups;
+
+       return 0;
+}
+
+static int nsp_pinmux_set(struct nsp_pinctrl *pinctrl,
+                         const struct nsp_pin_function *func,
+                         const struct nsp_pin_group *grp,
+                         struct nsp_mux_log *mux_log)
+{
+       const struct nsp_mux *mux = &grp->mux;
+       int i;
+       u32 val, mask;
+       unsigned long flags;
+       void __iomem *base_address;
+
+       for (i = 0; i < pinctrl->num_groups; i++) {
+               if ((mux->shift != mux_log[i].mux.shift) ||
+                       (mux->base != mux_log[i].mux.base))
+                       continue;
+
+               /* if this is a new configuration, just do it! */
+               if (!mux_log[i].is_configured)
+                       break;
+
+               /*
+                * IOMUX has been configured previously and one is trying to
+                * configure it to a different function
+                */
+               if (mux_log[i].mux.alt != mux->alt) {
+                       dev_err(pinctrl->dev,
+                               "double configuration error detected!\n");
+                       dev_err(pinctrl->dev, "func:%s grp:%s\n",
+                               func->name, grp->name);
+                       return -EINVAL;
+               }
+
+               return 0;
+       }
+       if (i == pinctrl->num_groups)
+               return -EINVAL;
+
+       mask = mux->mask;
+       mux_log[i].mux.alt = mux->alt;
+       mux_log[i].is_configured = true;
+
+       switch (mux->base) {
+       case NSP_MUX_BASE0:
+               base_address = pinctrl->base0;
+               break;
+
+       case NSP_MUX_BASE1:
+               base_address = pinctrl->base1;
+               break;
+
+       case NSP_MUX_BASE2:
+               base_address = pinctrl->base2;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&pinctrl->lock, flags);
+       val = readl(base_address);
+       val &= ~(mask << grp->mux.shift);
+       val |= grp->mux.alt << grp->mux.shift;
+       writel(val, base_address);
+       spin_unlock_irqrestore(&pinctrl->lock, flags);
+
+       return 0;
+}
+
+static int nsp_pinmux_enable(struct pinctrl_dev *pctrl_dev,
+                            unsigned int func_select, unsigned int grp_select)
+{
+       struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+       const struct nsp_pin_function *func;
+       const struct nsp_pin_group *grp;
+
+       if (grp_select > pinctrl->num_groups ||
+               func_select > pinctrl->num_functions)
+               return -EINVAL;
+
+       func = &pinctrl->functions[func_select];
+       grp = &pinctrl->groups[grp_select];
+
+       dev_dbg(pctrl_dev->dev, "func:%u name:%s grp:%u name:%s\n",
+               func_select, func->name, grp_select, grp->name);
+
+       dev_dbg(pctrl_dev->dev, "shift:%u alt:%u\n", grp->mux.shift,
+               grp->mux.alt);
+
+       return nsp_pinmux_set(pinctrl, func, grp, pinctrl->mux_log);
+}
+
+
+static int nsp_gpio_request_enable(struct pinctrl_dev *pctrl_dev,
+                                  struct pinctrl_gpio_range *range,
+                                  unsigned int pin)
+{
+       struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+       u32 *gpio_select = pctrl_dev->desc->pins[pin].drv_data;
+       u32 val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pinctrl->lock, flags);
+       val = readl(pinctrl->base0);
+       if ((val & BIT(pin)) != (*gpio_select << pin)) {
+               val &= ~BIT(pin);
+               val |= *gpio_select << pin;
+               writel(val, pinctrl->base0);
+       }
+       spin_unlock_irqrestore(&pinctrl->lock, flags);
+
+       return 0;
+}
+
+static void nsp_gpio_disable_free(struct pinctrl_dev *pctrl_dev,
+                                 struct pinctrl_gpio_range *range,
+                                 unsigned int pin)
+{
+       struct nsp_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+       u32 *gpio_select = pctrl_dev->desc->pins[pin].drv_data;
+       u32 val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pinctrl->lock, flags);
+       val = readl(pinctrl->base0);
+       if ((val & (1 << pin)) == (*gpio_select << pin)) {
+               val &= ~(1 << pin);
+               if (!(*gpio_select))
+                       val |= (1 << pin);
+               writel(val, pinctrl->base0);
+       }
+       spin_unlock_irqrestore(&pinctrl->lock, flags);
+}
+
+static struct pinmux_ops nsp_pinmux_ops = {
+       .get_functions_count = nsp_get_functions_count,
+       .get_function_name = nsp_get_function_name,
+       .get_function_groups = nsp_get_function_groups,
+       .set_mux = nsp_pinmux_enable,
+       .gpio_request_enable = nsp_gpio_request_enable,
+       .gpio_disable_free = nsp_gpio_disable_free,
+};
+
+static struct pinctrl_desc nsp_pinctrl_desc = {
+       .name = "nsp-pinmux",
+       .pctlops = &nsp_pinctrl_ops,
+       .pmxops = &nsp_pinmux_ops,
+};
+
+static int nsp_mux_log_init(struct nsp_pinctrl *pinctrl)
+{
+       struct nsp_mux_log *log;
+       unsigned int i;
+       u32 no_of_groups = ARRAY_SIZE(nsp_pin_groups);
+
+       pinctrl->mux_log = devm_kcalloc(pinctrl->dev, no_of_groups,
+                                       sizeof(struct nsp_mux_log),
+                                       GFP_KERNEL);
+       if (!pinctrl->mux_log)
+               return -ENOMEM;
+
+       for (i = 0; i < no_of_groups; i++) {
+               log = &pinctrl->mux_log[i];
+               log->mux.base = nsp_pin_groups[i].mux.base;
+               log->mux.shift = nsp_pin_groups[i].mux.shift;
+               log->mux.alt = 0;
+               log->is_configured = false;
+       }
+
+       return 0;
+}
+
+static int nsp_pinmux_probe(struct platform_device *pdev)
+{
+       struct nsp_pinctrl *pinctrl;
+       struct resource *res;
+       int i, ret;
+       struct pinctrl_pin_desc *pins;
+       unsigned int num_pins = ARRAY_SIZE(nsp_pins);
+
+       pinctrl = devm_kzalloc(&pdev->dev, sizeof(*pinctrl), GFP_KERNEL);
+       if (!pinctrl)
+               return -ENOMEM;
+       pinctrl->dev = &pdev->dev;
+       platform_set_drvdata(pdev, pinctrl);
+       spin_lock_init(&pinctrl->lock);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       pinctrl->base0 = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(pinctrl->base0))
+               return PTR_ERR(pinctrl->base0);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       pinctrl->base1 = devm_ioremap_nocache(&pdev->dev, res->start,
+                                             resource_size(res));
+       if (!pinctrl->base1) {
+               dev_err(&pdev->dev, "unable to map I/O space\n");
+               return -ENOMEM;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+       pinctrl->base2 = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(pinctrl->base2))
+               return PTR_ERR(pinctrl->base2);
+
+       ret = nsp_mux_log_init(pinctrl);
+       if (ret) {
+               dev_err(&pdev->dev, "unable to initialize IOMUX log\n");
+               return ret;
+       }
+
+       pins = devm_kcalloc(&pdev->dev, num_pins, sizeof(*pins), GFP_KERNEL);
+       if (!pins)
+               return -ENOMEM;
+
+       for (i = 0; i < num_pins; i++) {
+               pins[i].number = nsp_pins[i].pin;
+               pins[i].name = nsp_pins[i].name;
+               pins[i].drv_data = &nsp_pins[i].gpio_select;
+       }
+
+       pinctrl->groups = nsp_pin_groups;
+       pinctrl->num_groups = ARRAY_SIZE(nsp_pin_groups);
+       pinctrl->functions = nsp_pin_functions;
+       pinctrl->num_functions = ARRAY_SIZE(nsp_pin_functions);
+       nsp_pinctrl_desc.pins = pins;
+       nsp_pinctrl_desc.npins = num_pins;
+
+       pinctrl->pctl = devm_pinctrl_register(&pdev->dev, &nsp_pinctrl_desc,
+                                        pinctrl);
+       if (IS_ERR(pinctrl->pctl)) {
+               dev_err(&pdev->dev, "unable to register nsp IOMUX pinctrl\n");
+               return PTR_ERR(pinctrl->pctl);
+       }
+
+       return 0;
+}
+
+static const struct of_device_id nsp_pinmux_of_match[] = {
+       { .compatible = "brcm,nsp-pinmux" },
+       { }
+};
+
+static struct platform_driver nsp_pinmux_driver = {
+       .driver = {
+               .name = "nsp-pinmux",
+               .of_match_table = nsp_pinmux_of_match,
+       },
+       .probe = nsp_pinmux_probe,
+};
+
+static int __init nsp_pinmux_init(void)
+{
+       return platform_driver_register(&nsp_pinmux_driver);
+}
+arch_initcall(nsp_pinmux_init);
index 98d2a1b..fb38e20 100644 (file)
@@ -225,13 +225,14 @@ static void pinctrl_free_pindescs(struct pinctrl_dev *pctldev,
 }
 
 static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,
-                                   unsigned number, const char *name)
+                                   const struct pinctrl_pin_desc *pin)
 {
        struct pin_desc *pindesc;
 
-       pindesc = pin_desc_get(pctldev, number);
+       pindesc = pin_desc_get(pctldev, pin->number);
        if (pindesc != NULL) {
-               dev_err(pctldev->dev, "pin %d already registered\n", number);
+               dev_err(pctldev->dev, "pin %d already registered\n",
+                       pin->number);
                return -EINVAL;
        }
 
@@ -245,10 +246,10 @@ static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,
        pindesc->pctldev = pctldev;
 
        /* Copy basic pin info */
-       if (name) {
-               pindesc->name = name;
+       if (pin->name) {
+               pindesc->name = pin->name;
        } else {
-               pindesc->name = kasprintf(GFP_KERNEL, "PIN%u", number);
+               pindesc->name = kasprintf(GFP_KERNEL, "PIN%u", pin->number);
                if (pindesc->name == NULL) {
                        kfree(pindesc);
                        return -ENOMEM;
@@ -256,9 +257,11 @@ static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,
                pindesc->dynamic_name = true;
        }
 
-       radix_tree_insert(&pctldev->pin_desc_tree, number, pindesc);
+       pindesc->drv_data = pin->drv_data;
+
+       radix_tree_insert(&pctldev->pin_desc_tree, pin->number, pindesc);
        pr_debug("registered pin %d (%s) on %s\n",
-                number, pindesc->name, pctldev->desc->name);
+                pin->number, pindesc->name, pctldev->desc->name);
        return 0;
 }
 
@@ -270,8 +273,7 @@ static int pinctrl_register_pins(struct pinctrl_dev *pctldev,
        int ret = 0;
 
        for (i = 0; i < num_descs; i++) {
-               ret = pinctrl_register_one_pin(pctldev,
-                                              pins[i].number, pins[i].name);
+               ret = pinctrl_register_one_pin(pctldev, &pins[i]);
                if (ret)
                        return ret;
        }
@@ -1367,8 +1369,7 @@ static int pinctrl_pins_show(struct seq_file *s, void *what)
                if (desc == NULL)
                        continue;
 
-               seq_printf(s, "pin %d (%s) ", pin,
-                          desc->name ? desc->name : "unnamed");
+               seq_printf(s, "pin %d (%s) ", pin, desc->name);
 
                /* Driver-specific info per pin */
                if (ops->pin_dbg_show)
index ca08723..747c423 100644 (file)
@@ -134,6 +134,7 @@ struct pinctrl_setting {
  * @name: a name for the pin, e.g. the name of the pin/pad/finger on a
  *     datasheet or such
  * @dynamic_name: if the name of this pin was dynamically allocated
+ * @drv_data: driver-defined per-pin data. pinctrl core does not touch this
  * @mux_usecount: If zero, the pin is not claimed, and @owner should be NULL.
  *     If non-zero, this pin is claimed by @owner. This field is an integer
  *     rather than a boolean, since pinctrl_get() might process multiple
@@ -148,6 +149,7 @@ struct pin_desc {
        struct pinctrl_dev *pctldev;
        const char *name;
        bool dynamic_name;
+       void *drv_data;
        /* These fields only added when supporting pinmux drivers */
 #ifdef CONFIG_PINMUX
        unsigned mux_usecount;
index fe04e74..54dad89 100644 (file)
@@ -195,8 +195,13 @@ int pinctrl_dt_to_map(struct pinctrl *p)
                propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);
                prop = of_find_property(np, propname, &size);
                kfree(propname);
-               if (!prop)
+               if (!prop) {
+                       if (state == 0) {
+                               of_node_put(np);
+                               return -ENODEV;
+                       }
                        break;
+               }
                list = prop->value;
                size /= sizeof(*list);
 
index eccb474..7139175 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/mfd/syscon.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_address.h>
@@ -46,7 +45,7 @@ struct imx_pinctrl {
        const struct imx_pinctrl_soc_info *info;
 };
 
-static const inline struct imx_pin_group *imx_pinctrl_find_group_by_name(
+static inline const struct imx_pin_group *imx_pinctrl_find_group_by_name(
                                const struct imx_pinctrl_soc_info *info,
                                const char *name)
 {
@@ -513,13 +512,6 @@ static const struct pinconf_ops imx_pinconf_ops = {
        .pin_config_group_dbg_show = imx_pinconf_group_dbg_show,
 };
 
-static struct pinctrl_desc imx_pinctrl_desc = {
-       .pctlops = &imx_pctrl_ops,
-       .pmxops = &imx_pmx_ops,
-       .confops = &imx_pinconf_ops,
-       .owner = THIS_MODULE,
-};
-
 /*
  * Each pin represented in fsl,pins consists of 5 u32 PIN_FUNC_ID and
  * 1 u32 CONFIG, so 24 types in total for each pin.
@@ -722,6 +714,7 @@ int imx_pinctrl_probe(struct platform_device *pdev,
 {
        struct regmap_config config = { .name = "gpr" };
        struct device_node *dev_np = pdev->dev.of_node;
+       struct pinctrl_desc *imx_pinctrl_desc;
        struct device_node *np;
        struct imx_pinctrl *ipctl;
        struct resource *res;
@@ -776,9 +769,18 @@ int imx_pinctrl_probe(struct platform_device *pdev,
                }
        }
 
-       imx_pinctrl_desc.name = dev_name(&pdev->dev);
-       imx_pinctrl_desc.pins = info->pins;
-       imx_pinctrl_desc.npins = info->npins;
+       imx_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*imx_pinctrl_desc),
+                                       GFP_KERNEL);
+       if (!imx_pinctrl_desc)
+               return -ENOMEM;
+
+       imx_pinctrl_desc->name = dev_name(&pdev->dev);
+       imx_pinctrl_desc->pins = info->pins;
+       imx_pinctrl_desc->npins = info->npins;
+       imx_pinctrl_desc->pctlops = &imx_pctrl_ops,
+       imx_pinctrl_desc->pmxops = &imx_pmx_ops,
+       imx_pinctrl_desc->confops = &imx_pinconf_ops,
+       imx_pinctrl_desc->owner = THIS_MODULE,
 
        ret = imx_pinctrl_probe_dt(pdev, info);
        if (ret) {
@@ -789,7 +791,8 @@ int imx_pinctrl_probe(struct platform_device *pdev,
        ipctl->info = info;
        ipctl->dev = info->dev;
        platform_set_drvdata(pdev, ipctl);
-       ipctl->pctl = devm_pinctrl_register(&pdev->dev, &imx_pinctrl_desc, ipctl);
+       ipctl->pctl = devm_pinctrl_register(&pdev->dev,
+                                           imx_pinctrl_desc, ipctl);
        if (IS_ERR(ipctl->pctl)) {
                dev_err(&pdev->dev, "could not register IMX pinctrl driver\n");
                return PTR_ERR(ipctl->pctl);
index b4400cb..a4e9f43 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/machine.h>
@@ -157,7 +156,7 @@ static int imx1_read_bit(struct imx1_pinctrl *ipctl, unsigned int pin_id,
        return !!(readl(reg) & BIT(offset));
 }
 
-static const inline struct imx1_pin_group *imx1_pinctrl_find_group_by_name(
+static inline const struct imx1_pin_group *imx1_pinctrl_find_group_by_name(
                                const struct imx1_pinctrl_soc_info *info,
                                const char *name)
 {
index 0472345..fc8efc7 100644 (file)
@@ -9,7 +9,7 @@
  * (at your option) any later version.
  */
 
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -262,7 +262,6 @@ static const struct of_device_id imx1_pinctrl_of_match[] = {
        { .compatible = "fsl,imx1-iomuxc", },
        { }
 };
-MODULE_DEVICE_TABLE(of, imx1_pinctrl_of_match);
 
 static struct platform_driver imx1_pinctrl_driver = {
        .driver = {
@@ -270,8 +269,4 @@ static struct platform_driver imx1_pinctrl_driver = {
                .of_match_table = imx1_pinctrl_of_match,
        },
 };
-module_platform_driver_probe(imx1_pinctrl_driver, imx1_pinctrl_probe);
-
-MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
-MODULE_DESCRIPTION("Freescale i.MX1 pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver_probe(imx1_pinctrl_driver, imx1_pinctrl_probe);
index aa1221f..73e26bc 100644 (file)
@@ -9,7 +9,7 @@
  * (at your option) any later version.
  */
 
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -325,7 +325,6 @@ static const struct of_device_id imx21_pinctrl_of_match[] = {
        { .compatible = "fsl,imx21-iomuxc", },
        { }
 };
-MODULE_DEVICE_TABLE(of, imx21_pinctrl_of_match);
 
 static struct platform_driver imx21_pinctrl_driver = {
        .driver = {
@@ -333,8 +332,4 @@ static struct platform_driver imx21_pinctrl_driver = {
                .of_match_table = imx21_pinctrl_of_match,
        },
 };
-module_platform_driver_probe(imx21_pinctrl_driver, imx21_pinctrl_probe);
-
-MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
-MODULE_DESCRIPTION("Freescale i.MX21 pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver_probe(imx21_pinctrl_driver, imx21_pinctrl_probe);
index 955cbf4..89b4f16 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Freescale i.MX23 pinctrl driver
+ *
+ * Author: Shawn Guo <shawn.guo@linaro.org>
  * Copyright 2012 Freescale Semiconductor, Inc.
  *
  * The code contained herein is licensed under the GNU General Public
@@ -10,7 +13,6 @@
  */
 
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
 #include "pinctrl-mxs.h"
@@ -276,15 +278,14 @@ static const struct of_device_id imx23_pinctrl_of_match[] = {
        { .compatible = "fsl,imx23-pinctrl", },
        { /* sentinel */ }
 };
-MODULE_DEVICE_TABLE(of, imx23_pinctrl_of_match);
 
 static struct platform_driver imx23_pinctrl_driver = {
        .driver = {
                .name = "imx23-pinctrl",
+               .suppress_bind_attrs = true,
                .of_match_table = imx23_pinctrl_of_match,
        },
        .probe = imx23_pinctrl_probe,
-       .remove = mxs_pinctrl_remove,
 };
 
 static int __init imx23_pinctrl_init(void)
@@ -292,13 +293,3 @@ static int __init imx23_pinctrl_init(void)
        return platform_driver_register(&imx23_pinctrl_driver);
 }
 postcore_initcall(imx23_pinctrl_init);
-
-static void __exit imx23_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx23_pinctrl_driver);
-}
-module_exit(imx23_pinctrl_exit);
-
-MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
-MODULE_DESCRIPTION("Freescale i.MX23 pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 81ad546..d7367fa 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -338,12 +337,3 @@ static int __init imx25_pinctrl_init(void)
        return platform_driver_register(&imx25_pinctrl_driver);
 }
 arch_initcall(imx25_pinctrl_init);
-
-static void __exit imx25_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx25_pinctrl_driver);
-}
-module_exit(imx25_pinctrl_exit);
-MODULE_AUTHOR("Denis Carikli <denis@eukrea.com>");
-MODULE_DESCRIPTION("Freescale IMX25 pinctrl driver");
-MODULE_LICENSE("GPL v2");
index f828fbb..e599203 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -412,12 +411,3 @@ static int __init imx27_pinctrl_init(void)
        return platform_driver_register(&imx27_pinctrl_driver);
 }
 arch_initcall(imx27_pinctrl_init);
-
-static void __exit imx27_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx27_pinctrl_driver);
-}
-module_exit(imx27_pinctrl_exit);
-MODULE_AUTHOR("Markus Pargmann <mpa@pengutronix.de>");
-MODULE_DESCRIPTION("Freescale IMX27 pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 5082efe..295236d 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Freescale i.MX28 pinctrl driver
+ *
+ * Author: Shawn Guo <shawn.guo@linaro.org>
  * Copyright 2012 Freescale Semiconductor, Inc.
  *
  * The code contained herein is licensed under the GNU General Public
@@ -10,7 +13,6 @@
  */
 
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
 #include "pinctrl-mxs.h"
@@ -392,15 +394,14 @@ static const struct of_device_id imx28_pinctrl_of_match[] = {
        { .compatible = "fsl,imx28-pinctrl", },
        { /* sentinel */ }
 };
-MODULE_DEVICE_TABLE(of, imx28_pinctrl_of_match);
 
 static struct platform_driver imx28_pinctrl_driver = {
        .driver = {
                .name = "imx28-pinctrl",
+               .suppress_bind_attrs = true,
                .of_match_table = imx28_pinctrl_of_match,
        },
        .probe = imx28_pinctrl_probe,
-       .remove = mxs_pinctrl_remove,
 };
 
 static int __init imx28_pinctrl_init(void)
@@ -408,13 +409,3 @@ static int __init imx28_pinctrl_init(void)
        return platform_driver_register(&imx28_pinctrl_driver);
 }
 postcore_initcall(imx28_pinctrl_init);
-
-static void __exit imx28_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx28_pinctrl_driver);
-}
-module_exit(imx28_pinctrl_exit);
-
-MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
-MODULE_DESCRIPTION("Freescale i.MX28 pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 13eb224..6315ba6 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -1028,12 +1027,3 @@ static int __init imx35_pinctrl_init(void)
        return platform_driver_register(&imx35_pinctrl_driver);
 }
 arch_initcall(imx35_pinctrl_init);
-
-static void __exit imx35_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx35_pinctrl_driver);
-}
-module_exit(imx35_pinctrl_exit);
-MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>");
-MODULE_DESCRIPTION("Freescale IMX35 pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 95a36c8..8e3a17d 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -415,11 +414,3 @@ static int __init imx50_pinctrl_init(void)
        return platform_driver_register(&imx50_pinctrl_driver);
 }
 arch_initcall(imx50_pinctrl_init);
-
-static void __exit imx50_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx50_pinctrl_driver);
-}
-module_exit(imx50_pinctrl_exit);
-MODULE_DESCRIPTION("Freescale IMX50 pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 0863e52..eeac64b 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -791,12 +790,3 @@ static int __init imx51_pinctrl_init(void)
        return platform_driver_register(&imx51_pinctrl_driver);
 }
 arch_initcall(imx51_pinctrl_init);
-
-static void __exit imx51_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx51_pinctrl_driver);
-}
-module_exit(imx51_pinctrl_exit);
-MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>");
-MODULE_DESCRIPTION("Freescale IMX51 pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 64c9cbe..46a9572 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -478,12 +477,3 @@ static int __init imx53_pinctrl_init(void)
        return platform_driver_register(&imx53_pinctrl_driver);
 }
 arch_initcall(imx53_pinctrl_init);
-
-static void __exit imx53_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx53_pinctrl_driver);
-}
-module_exit(imx53_pinctrl_exit);
-MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>");
-MODULE_DESCRIPTION("Freescale IMX53 pinctrl driver");
-MODULE_LICENSE("GPL v2");
index de17bac..3f25ca5 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Freescale imx6dl pinctrl driver
+ *
+ * Author: Shawn Guo <shawn.guo@linaro.org>
  * Copyright (C) 2013 Freescale Semiconductor, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -9,7 +12,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -484,13 +486,3 @@ static int __init imx6dl_pinctrl_init(void)
        return platform_driver_register(&imx6dl_pinctrl_driver);
 }
 arch_initcall(imx6dl_pinctrl_init);
-
-static void __exit imx6dl_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx6dl_pinctrl_driver);
-}
-module_exit(imx6dl_pinctrl_exit);
-
-MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
-MODULE_DESCRIPTION("Freescale imx6dl pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 55cd8a0..d61651c 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -490,12 +489,3 @@ static int __init imx6q_pinctrl_init(void)
        return platform_driver_register(&imx6q_pinctrl_driver);
 }
 arch_initcall(imx6q_pinctrl_init);
-
-static void __exit imx6q_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx6q_pinctrl_driver);
-}
-module_exit(imx6q_pinctrl_exit);
-MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>");
-MODULE_DESCRIPTION("Freescale IMX6Q pinctrl driver");
-MODULE_LICENSE("GPL v2");
index bf455b8..d023f6b 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Freescale imx6sl pinctrl driver
+ *
+ * Author: Shawn Guo <shawn.guo@linaro.org>
  * Copyright (C) 2013 Freescale Semiconductor, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -9,7 +12,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -371,7 +373,6 @@ static const struct of_device_id imx6sl_pinctrl_of_match[] = {
        { .compatible = "fsl,imx6sl-iomuxc", },
        { /* sentinel */ }
 };
-MODULE_DEVICE_TABLE(of, imx6sl_pinctrl_of_match);
 
 static int imx6sl_pinctrl_probe(struct platform_device *pdev)
 {
@@ -391,13 +392,3 @@ static int __init imx6sl_pinctrl_init(void)
        return platform_driver_register(&imx6sl_pinctrl_driver);
 }
 arch_initcall(imx6sl_pinctrl_init);
-
-static void __exit imx6sl_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx6sl_pinctrl_driver);
-}
-module_exit(imx6sl_pinctrl_exit);
-
-MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
-MODULE_DESCRIPTION("Freescale imx6sl pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 84118c3..898b781 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Freescale imx6sx pinctrl driver
+ *
+ * Author: Anson Huang <Anson.Huang@freescale.com>
  * Copyright (C) 2014 Freescale Semiconductor, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -9,7 +12,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -394,13 +396,3 @@ static int __init imx6sx_pinctrl_init(void)
        return platform_driver_register(&imx6sx_pinctrl_driver);
 }
 arch_initcall(imx6sx_pinctrl_init);
-
-static void __exit imx6sx_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx6sx_pinctrl_driver);
-}
-module_exit(imx6sx_pinctrl_exit);
-
-MODULE_AUTHOR("Anson Huang <Anson.Huang@freescale.com>");
-MODULE_DESCRIPTION("Freescale imx6sx pinctrl driver");
-MODULE_LICENSE("GPL v2");
index c707fdd..1aeb840 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Freescale imx6ul pinctrl driver
+ *
+ * Author: Anson Huang <Anson.Huang@freescale.com>
  * Copyright (C) 2015 Freescale Semiconductor, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -9,7 +12,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -310,13 +312,3 @@ static int __init imx6ul_pinctrl_init(void)
        return platform_driver_register(&imx6ul_pinctrl_driver);
 }
 arch_initcall(imx6ul_pinctrl_init);
-
-static void __exit imx6ul_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx6ul_pinctrl_driver);
-}
-module_exit(imx6ul_pinctrl_exit);
-
-MODULE_AUTHOR("Anson Huang <Anson.Huang@freescale.com>");
-MODULE_DESCRIPTION("Freescale imx6ul pinctrl driver");
-MODULE_LICENSE("GPL v2");
index d30d91f..a465a66 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Freescale imx7d pinctrl driver
+ *
+ * Author: Anson Huang <Anson.Huang@freescale.com>
  * Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -9,7 +12,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -402,13 +404,3 @@ static int __init imx7d_pinctrl_init(void)
        return platform_driver_register(&imx7d_pinctrl_driver);
 }
 arch_initcall(imx7d_pinctrl_init);
-
-static void __exit imx7d_pinctrl_exit(void)
-{
-       platform_driver_unregister(&imx7d_pinctrl_driver);
-}
-module_exit(imx7d_pinctrl_exit);
-
-MODULE_AUTHOR("Anson Huang <Anson.Huang@freescale.com>");
-MODULE_DESCRIPTION("Freescale imx7d pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 6bbda6b..41b5b07 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/pinctrl/machine.h>
@@ -553,14 +552,3 @@ err:
        return ret;
 }
 EXPORT_SYMBOL_GPL(mxs_pinctrl_probe);
-
-int mxs_pinctrl_remove(struct platform_device *pdev)
-{
-       struct mxs_pinctrl_data *d = platform_get_drvdata(pdev);
-
-       pinctrl_unregister(d->pctl);
-       iounmap(d->base);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(mxs_pinctrl_remove);
index fdd88d0..34dbf75 100644 (file)
@@ -86,6 +86,5 @@ struct mxs_pinctrl_soc_data {
 
 int mxs_pinctrl_probe(struct platform_device *pdev,
                      struct mxs_pinctrl_soc_data *soc);
-int mxs_pinctrl_remove(struct platform_device *pdev);
 
 #endif /* __PINCTRL_MXS_H */
index 6d81be0..2b1e198 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -325,12 +324,3 @@ static int __init vf610_pinctrl_init(void)
        return platform_driver_register(&vf610_pinctrl_driver);
 }
 arch_initcall(vf610_pinctrl_init);
-
-static void __exit vf610_pinctrl_exit(void)
-{
-       platform_driver_unregister(&vf610_pinctrl_driver);
-}
-module_exit(vf610_pinctrl_exit);
-
-MODULE_DESCRIPTION("Freescale VF610 pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 1c74e03..00fb055 100644 (file)
@@ -29,6 +29,17 @@ config PINCTRL_CHERRYVIEW
          Cherryview/Braswell pinctrl driver provides an interface that
          allows configuring of SoC pins and using them as GPIOs.
 
+config PINCTRL_MERRIFIELD
+       tristate "Intel Merrifield pinctrl driver"
+       depends on X86_INTEL_MID
+       select PINMUX
+       select PINCONF
+       select GENERIC_PINCONF
+       help
+         Merrifield Family-Level Interface Shim (FLIS) driver provides an
+         interface that allows configuring of SoC pins and using them as
+         GPIOs.
+
 config PINCTRL_INTEL
        tristate
        select PINMUX
index 03bc68e..3080307 100644 (file)
@@ -2,6 +2,7 @@
 
 obj-$(CONFIG_PINCTRL_BAYTRAIL)         += pinctrl-baytrail.o
 obj-$(CONFIG_PINCTRL_CHERRYVIEW)       += pinctrl-cherryview.o
+obj-$(CONFIG_PINCTRL_MERRIFIELD)       += pinctrl-merrifield.o
 obj-$(CONFIG_PINCTRL_INTEL)            += pinctrl-intel.o
 obj-$(CONFIG_PINCTRL_BROXTON)          += pinctrl-broxton.o
 obj-$(CONFIG_PINCTRL_SUNRISEPOINT)     += pinctrl-sunrisepoint.o
index 7abfd42..d22a9fe 100644 (file)
@@ -15,7 +15,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/bitops.h>
@@ -1822,17 +1821,6 @@ static int byt_pinctrl_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int byt_pinctrl_remove(struct platform_device *pdev)
-{
-       struct byt_gpio *vg = platform_get_drvdata(pdev);
-
-       pm_runtime_disable(&pdev->dev);
-       gpiochip_remove(&vg->chip);
-       pinctrl_unregister(vg->pctl_dev);
-
-       return 0;
-}
-
 #ifdef CONFIG_PM_SLEEP
 static int byt_gpio_suspend(struct device *dev)
 {
@@ -1930,10 +1918,11 @@ static const struct dev_pm_ops byt_gpio_pm_ops = {
 
 static struct platform_driver byt_gpio_driver = {
        .probe          = byt_pinctrl_probe,
-       .remove         = byt_pinctrl_remove,
        .driver         = {
-               .name   = "byt_gpio",
-               .pm     = &byt_gpio_pm_ops,
+               .name                   = "byt_gpio",
+               .pm                     = &byt_gpio_pm_ops,
+               .suppress_bind_attrs    = true,
+
                .acpi_match_table = ACPI_PTR(byt_gpio_acpi_match),
        },
 };
@@ -1943,9 +1932,3 @@ static int __init byt_gpio_init(void)
        return platform_driver_register(&byt_gpio_driver);
 }
 subsys_initcall(byt_gpio_init);
-
-static void __exit byt_gpio_exit(void)
-{
-       platform_driver_unregister(&byt_gpio_driver);
-}
-module_exit(byt_gpio_exit);
index 5979d38..59cb7a6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Intel Broxton SoC pinctrl/GPIO driver
  *
- * Copyright (C) 2015, Intel Corporation
+ * Copyright (C) 2015, 2016 Intel Corporation
  * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -1003,29 +1003,46 @@ static const struct acpi_device_id bxt_pinctrl_acpi_match[] = {
 };
 MODULE_DEVICE_TABLE(acpi, bxt_pinctrl_acpi_match);
 
+static const struct platform_device_id bxt_pinctrl_platform_ids[] = {
+       { "apl-pinctrl", (kernel_ulong_t)&apl_pinctrl_soc_data },
+       { "broxton-pinctrl", (kernel_ulong_t)&bxt_pinctrl_soc_data },
+       { },
+};
+
 static int bxt_pinctrl_probe(struct platform_device *pdev)
 {
        const struct intel_pinctrl_soc_data *soc_data = NULL;
        const struct intel_pinctrl_soc_data **soc_table;
-       const struct acpi_device_id *id;
        struct acpi_device *adev;
        int i;
 
        adev = ACPI_COMPANION(&pdev->dev);
-       if (!adev)
-               return -ENODEV;
+       if (adev) {
+               const struct acpi_device_id *id;
 
-       id = acpi_match_device(bxt_pinctrl_acpi_match, &pdev->dev);
-       if (!id)
-               return -ENODEV;
+               id = acpi_match_device(bxt_pinctrl_acpi_match, &pdev->dev);
+               if (!id)
+                       return -ENODEV;
 
-       soc_table = (const struct intel_pinctrl_soc_data **)id->driver_data;
+               soc_table = (const struct intel_pinctrl_soc_data **)
+                       id->driver_data;
 
-       for (i = 0; soc_table[i]; i++) {
-               if (!strcmp(adev->pnp.unique_id, soc_table[i]->uid)) {
-                       soc_data = soc_table[i];
-                       break;
+               for (i = 0; soc_table[i]; i++) {
+                       if (!strcmp(adev->pnp.unique_id, soc_table[i]->uid)) {
+                               soc_data = soc_table[i];
+                               break;
+                       }
                }
+       } else {
+               const struct platform_device_id *pid;
+
+               pid = platform_get_device_id(pdev);
+               if (!pid)
+                       return -ENODEV;
+
+               soc_table = (const struct intel_pinctrl_soc_data **)
+                       pid->driver_data;
+               soc_data = soc_table[pdev->id];
        }
 
        if (!soc_data)
@@ -1047,6 +1064,7 @@ static struct platform_driver bxt_pinctrl_driver = {
                .acpi_match_table = bxt_pinctrl_acpi_match,
                .pm = &bxt_pinctrl_pm_ops,
        },
+       .id_table = bxt_pinctrl_platform_ids,
 };
 
 static int __init bxt_pinctrl_init(void)
@@ -1064,3 +1082,4 @@ module_exit(bxt_pinctrl_exit);
 MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
 MODULE_DESCRIPTION("Intel Broxton SoC pinctrl/GPIO driver");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:broxton-pinctrl");
index ac4f564..5749a4e 100644 (file)
@@ -160,7 +160,6 @@ struct chv_pin_context {
  * @pctldev: Pointer to the pin controller device
  * @chip: GPIO chip in this pin controller
  * @regs: MMIO registers
- * @lock: Lock to serialize register accesses
  * @intr_lines: Stores mapping between 16 HW interrupt wires and GPIO
  *             offset (in GPIO number space)
  * @community: Community this pinctrl instance represents
@@ -174,7 +173,6 @@ struct chv_pinctrl {
        struct pinctrl_dev *pctldev;
        struct gpio_chip chip;
        void __iomem *regs;
-       raw_spinlock_t lock;
        unsigned intr_lines[16];
        const struct chv_community *community;
        u32 saved_intmask;
@@ -657,6 +655,17 @@ static const struct chv_community *chv_communities[] = {
        &southeast_community,
 };
 
+/*
+ * Lock to serialize register accesses
+ *
+ * Due to a silicon issue, a shared lock must be used to prevent
+ * concurrent accesses across the 4 GPIO controllers.
+ *
+ * See Intel Atom Z8000 Processor Series Specification Update (Rev. 005),
+ * errata #CHT34, for further information.
+ */
+static DEFINE_RAW_SPINLOCK(chv_lock);
+
 static void __iomem *chv_padreg(struct chv_pinctrl *pctrl, unsigned offset,
                                unsigned reg)
 {
@@ -718,13 +727,13 @@ static void chv_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
        u32 ctrl0, ctrl1;
        bool locked;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        ctrl0 = readl(chv_padreg(pctrl, offset, CHV_PADCTRL0));
        ctrl1 = readl(chv_padreg(pctrl, offset, CHV_PADCTRL1));
        locked = chv_pad_locked(pctrl, offset);
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        if (ctrl0 & CHV_PADCTRL0_GPIOEN) {
                seq_puts(s, "GPIO ");
@@ -787,14 +796,14 @@ static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function,
 
        grp = &pctrl->community->groups[group];
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        /* Check first that the pad is not locked */
        for (i = 0; i < grp->npins; i++) {
                if (chv_pad_locked(pctrl, grp->pins[i])) {
                        dev_warn(pctrl->dev, "unable to set mode for locked pin %u\n",
                                 grp->pins[i]);
-                       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+                       raw_spin_unlock_irqrestore(&chv_lock, flags);
                        return -EBUSY;
                }
        }
@@ -837,7 +846,7 @@ static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function,
                        pin, altfunc->mode, altfunc->invert_oe ? "" : "not ");
        }
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        return 0;
 }
@@ -851,13 +860,13 @@ static int chv_gpio_request_enable(struct pinctrl_dev *pctldev,
        void __iomem *reg;
        u32 value;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        if (chv_pad_locked(pctrl, offset)) {
                value = readl(chv_padreg(pctrl, offset, CHV_PADCTRL0));
                if (!(value & CHV_PADCTRL0_GPIOEN)) {
                        /* Locked so cannot enable */
-                       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+                       raw_spin_unlock_irqrestore(&chv_lock, flags);
                        return -EBUSY;
                }
        } else {
@@ -897,7 +906,7 @@ static int chv_gpio_request_enable(struct pinctrl_dev *pctldev,
                chv_writel(value, reg);
        }
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        return 0;
 }
@@ -911,13 +920,13 @@ static void chv_gpio_disable_free(struct pinctrl_dev *pctldev,
        void __iomem *reg;
        u32 value;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        reg = chv_padreg(pctrl, offset, CHV_PADCTRL0);
        value = readl(reg) & ~CHV_PADCTRL0_GPIOEN;
        chv_writel(value, reg);
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 }
 
 static int chv_gpio_set_direction(struct pinctrl_dev *pctldev,
@@ -929,7 +938,7 @@ static int chv_gpio_set_direction(struct pinctrl_dev *pctldev,
        unsigned long flags;
        u32 ctrl0;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        ctrl0 = readl(reg) & ~CHV_PADCTRL0_GPIOCFG_MASK;
        if (input)
@@ -938,7 +947,7 @@ static int chv_gpio_set_direction(struct pinctrl_dev *pctldev,
                ctrl0 |= CHV_PADCTRL0_GPIOCFG_GPO << CHV_PADCTRL0_GPIOCFG_SHIFT;
        chv_writel(ctrl0, reg);
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        return 0;
 }
@@ -963,10 +972,10 @@ static int chv_config_get(struct pinctrl_dev *pctldev, unsigned pin,
        u16 arg = 0;
        u32 term;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
        ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
        ctrl1 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL1));
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        term = (ctrl0 & CHV_PADCTRL0_TERM_MASK) >> CHV_PADCTRL0_TERM_SHIFT;
 
@@ -1040,7 +1049,7 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin,
        unsigned long flags;
        u32 ctrl0, pull;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
        ctrl0 = readl(reg);
 
        switch (param) {
@@ -1063,7 +1072,7 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin,
                        pull = CHV_PADCTRL0_TERM_20K << CHV_PADCTRL0_TERM_SHIFT;
                        break;
                default:
-                       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+                       raw_spin_unlock_irqrestore(&chv_lock, flags);
                        return -EINVAL;
                }
 
@@ -1081,7 +1090,7 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin,
                        pull = CHV_PADCTRL0_TERM_20K << CHV_PADCTRL0_TERM_SHIFT;
                        break;
                default:
-                       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+                       raw_spin_unlock_irqrestore(&chv_lock, flags);
                        return -EINVAL;
                }
 
@@ -1089,12 +1098,33 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin,
                break;
 
        default:
-               raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+               raw_spin_unlock_irqrestore(&chv_lock, flags);
                return -EINVAL;
        }
 
        chv_writel(ctrl0, reg);
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
+
+       return 0;
+}
+
+static int chv_config_set_oden(struct chv_pinctrl *pctrl, unsigned int pin,
+                              bool enable)
+{
+       void __iomem *reg = chv_padreg(pctrl, pin, CHV_PADCTRL1);
+       unsigned long flags;
+       u32 ctrl1;
+
+       raw_spin_lock_irqsave(&chv_lock, flags);
+       ctrl1 = readl(reg);
+
+       if (enable)
+               ctrl1 |= CHV_PADCTRL1_ODEN;
+       else
+               ctrl1 &= ~CHV_PADCTRL1_ODEN;
+
+       chv_writel(ctrl1, reg);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        return 0;
 }
@@ -1123,6 +1153,18 @@ static int chv_config_set(struct pinctrl_dev *pctldev, unsigned pin,
                                return ret;
                        break;
 
+               case PIN_CONFIG_DRIVE_PUSH_PULL:
+                       ret = chv_config_set_oden(pctrl, pin, false);
+                       if (ret)
+                               return ret;
+                       break;
+
+               case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+                       ret = chv_config_set_oden(pctrl, pin, true);
+                       if (ret)
+                               return ret;
+                       break;
+
                default:
                        return -ENOTSUPP;
                }
@@ -1134,10 +1176,52 @@ static int chv_config_set(struct pinctrl_dev *pctldev, unsigned pin,
        return 0;
 }
 
+static int chv_config_group_get(struct pinctrl_dev *pctldev,
+                               unsigned int group,
+                               unsigned long *config)
+{
+       const unsigned int *pins;
+       unsigned int npins;
+       int ret;
+
+       ret = chv_get_group_pins(pctldev, group, &pins, &npins);
+       if (ret)
+               return ret;
+
+       ret = chv_config_get(pctldev, pins[0], config);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int chv_config_group_set(struct pinctrl_dev *pctldev,
+                               unsigned int group, unsigned long *configs,
+                               unsigned int num_configs)
+{
+       const unsigned int *pins;
+       unsigned int npins;
+       int i, ret;
+
+       ret = chv_get_group_pins(pctldev, group, &pins, &npins);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < npins; i++) {
+               ret = chv_config_set(pctldev, pins[i], configs, num_configs);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static const struct pinconf_ops chv_pinconf_ops = {
        .is_generic = true,
        .pin_config_set = chv_config_set,
        .pin_config_get = chv_config_get,
+       .pin_config_group_get = chv_config_group_get,
+       .pin_config_group_set = chv_config_group_set,
 };
 
 static struct pinctrl_desc chv_pinctrl_desc = {
@@ -1160,9 +1244,9 @@ static int chv_gpio_get(struct gpio_chip *chip, unsigned offset)
        unsigned long flags;
        u32 ctrl0, cfg;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
        ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        cfg = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK;
        cfg >>= CHV_PADCTRL0_GPIOCFG_SHIFT;
@@ -1180,7 +1264,7 @@ static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        void __iomem *reg;
        u32 ctrl0;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        reg = chv_padreg(pctrl, pin, CHV_PADCTRL0);
        ctrl0 = readl(reg);
@@ -1192,7 +1276,7 @@ static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 
        chv_writel(ctrl0, reg);
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 }
 
 static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
@@ -1202,9 +1286,9 @@ static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
        u32 ctrl0, direction;
        unsigned long flags;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
        ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        direction = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK;
        direction >>= CHV_PADCTRL0_GPIOCFG_SHIFT;
@@ -1242,14 +1326,14 @@ static void chv_gpio_irq_ack(struct irq_data *d)
        int pin = chv_gpio_offset_to_pin(pctrl, irqd_to_hwirq(d));
        u32 intr_line;
 
-       raw_spin_lock(&pctrl->lock);
+       raw_spin_lock(&chv_lock);
 
        intr_line = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
        intr_line &= CHV_PADCTRL0_INTSEL_MASK;
        intr_line >>= CHV_PADCTRL0_INTSEL_SHIFT;
        chv_writel(BIT(intr_line), pctrl->regs + CHV_INTSTAT);
 
-       raw_spin_unlock(&pctrl->lock);
+       raw_spin_unlock(&chv_lock);
 }
 
 static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
@@ -1260,7 +1344,7 @@ static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
        u32 value, intr_line;
        unsigned long flags;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        intr_line = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
        intr_line &= CHV_PADCTRL0_INTSEL_MASK;
@@ -1273,7 +1357,7 @@ static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
                value |= BIT(intr_line);
        chv_writel(value, pctrl->regs + CHV_INTMASK);
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 }
 
 static void chv_gpio_irq_mask(struct irq_data *d)
@@ -1307,7 +1391,7 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d)
                unsigned long flags;
                u32 intsel, value;
 
-               raw_spin_lock_irqsave(&pctrl->lock, flags);
+               raw_spin_lock_irqsave(&chv_lock, flags);
                intsel = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
                intsel &= CHV_PADCTRL0_INTSEL_MASK;
                intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
@@ -1322,7 +1406,7 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d)
                        irq_set_handler_locked(d, handler);
                        pctrl->intr_lines[intsel] = offset;
                }
-               raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+               raw_spin_unlock_irqrestore(&chv_lock, flags);
        }
 
        chv_gpio_irq_unmask(d);
@@ -1338,7 +1422,7 @@ static int chv_gpio_irq_type(struct irq_data *d, unsigned type)
        unsigned long flags;
        u32 value;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        /*
         * Pins which can be used as shared interrupt are configured in
@@ -1387,7 +1471,7 @@ static int chv_gpio_irq_type(struct irq_data *d, unsigned type)
        else if (type & IRQ_TYPE_LEVEL_MASK)
                irq_set_handler_locked(d, handle_level_irq);
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        return 0;
 }
@@ -1499,7 +1583,6 @@ static int chv_pinctrl_probe(struct platform_device *pdev)
        if (i == ARRAY_SIZE(chv_communities))
                return -ENODEV;
 
-       raw_spin_lock_init(&pctrl->lock);
        pctrl->dev = &pdev->dev;
 
 #ifdef CONFIG_PM_SLEEP
index 3584e50..257cab1 100644 (file)
@@ -89,7 +89,7 @@ struct intel_pinctrl_context {
  */
 struct intel_pinctrl {
        struct device *dev;
-       spinlock_t lock;
+       raw_spinlock_t lock;
        struct pinctrl_desc pctldesc;
        struct pinctrl_dev *pctldev;
        struct gpio_chip chip;
@@ -318,7 +318,7 @@ static int intel_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function,
        unsigned long flags;
        int i;
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        /*
         * All pins in the groups needs to be accessible and writable
@@ -326,7 +326,7 @@ static int intel_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function,
         */
        for (i = 0; i < grp->npins; i++) {
                if (!intel_pad_usable(pctrl, grp->pins[i])) {
-                       spin_unlock_irqrestore(&pctrl->lock, flags);
+                       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
                        return -EBUSY;
                }
        }
@@ -345,7 +345,7 @@ static int intel_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function,
                writel(value, padcfg0);
        }
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 
        return 0;
 }
@@ -359,10 +359,10 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
        unsigned long flags;
        u32 value;
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        if (!intel_pad_usable(pctrl, pin)) {
-               spin_unlock_irqrestore(&pctrl->lock, flags);
+               raw_spin_unlock_irqrestore(&pctrl->lock, flags);
                return -EBUSY;
        }
 
@@ -377,7 +377,7 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
        value |= PADCFG0_GPIOTXDIS;
        writel(value, padcfg0);
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 
        return 0;
 }
@@ -391,7 +391,7 @@ static int intel_gpio_set_direction(struct pinctrl_dev *pctldev,
        unsigned long flags;
        u32 value;
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
 
@@ -402,7 +402,7 @@ static int intel_gpio_set_direction(struct pinctrl_dev *pctldev,
                value &= ~PADCFG0_GPIOTXDIS;
        writel(value, padcfg0);
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 
        return 0;
 }
@@ -490,7 +490,7 @@ static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned pin,
        int ret = 0;
        u32 value;
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        padcfg1 = intel_get_padcfg(pctrl, pin, PADCFG1);
        value = readl(padcfg1);
@@ -544,7 +544,7 @@ static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned pin,
        if (!ret)
                writel(value, padcfg1);
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 
        return ret;
 }
@@ -611,14 +611,14 @@ static void intel_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
                unsigned long flags;
                u32 padcfg0;
 
-               spin_lock_irqsave(&pctrl->lock, flags);
+               raw_spin_lock_irqsave(&pctrl->lock, flags);
                padcfg0 = readl(reg);
                if (value)
                        padcfg0 |= PADCFG0_GPIOTXSTATE;
                else
                        padcfg0 &= ~PADCFG0_GPIOTXSTATE;
                writel(padcfg0, reg);
-               spin_unlock_irqrestore(&pctrl->lock, flags);
+               raw_spin_unlock_irqrestore(&pctrl->lock, flags);
        }
 }
 
@@ -651,7 +651,7 @@ static void intel_gpio_irq_ack(struct irq_data *d)
        const struct intel_community *community;
        unsigned pin = irqd_to_hwirq(d);
 
-       spin_lock(&pctrl->lock);
+       raw_spin_lock(&pctrl->lock);
 
        community = intel_get_community(pctrl, pin);
        if (community) {
@@ -662,7 +662,7 @@ static void intel_gpio_irq_ack(struct irq_data *d)
                writel(BIT(gpp_offset), community->regs + GPI_IS + gpp * 4);
        }
 
-       spin_unlock(&pctrl->lock);
+       raw_spin_unlock(&pctrl->lock);
 }
 
 static void intel_gpio_irq_enable(struct irq_data *d)
@@ -673,7 +673,7 @@ static void intel_gpio_irq_enable(struct irq_data *d)
        unsigned pin = irqd_to_hwirq(d);
        unsigned long flags;
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        community = intel_get_community(pctrl, pin);
        if (community) {
@@ -691,7 +691,7 @@ static void intel_gpio_irq_enable(struct irq_data *d)
                writel(value, community->regs + community->ie_offset + gpp * 4);
        }
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 }
 
 static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
@@ -702,7 +702,7 @@ static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
        unsigned pin = irqd_to_hwirq(d);
        unsigned long flags;
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        community = intel_get_community(pctrl, pin);
        if (community) {
@@ -721,7 +721,7 @@ static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
                writel(value, reg);
        }
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 }
 
 static void intel_gpio_irq_mask(struct irq_data *d)
@@ -757,7 +757,7 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned type)
                return -EPERM;
        }
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        value = readl(reg);
 
@@ -784,7 +784,7 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned type)
        else if (type & IRQ_TYPE_LEVEL_MASK)
                irq_set_handler_locked(d, handle_level_irq);
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 
        return 0;
 }
@@ -796,12 +796,15 @@ static int intel_gpio_irq_wake(struct irq_data *d, unsigned int on)
        const struct intel_community *community;
        unsigned pin = irqd_to_hwirq(d);
        unsigned padno, gpp, gpp_offset;
+       unsigned long flags;
        u32 gpe_en;
 
        community = intel_get_community(pctrl, pin);
        if (!community)
                return -EINVAL;
 
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
+
        padno = pin_to_padno(community, pin);
        gpp = padno / community->gpp_size;
        gpp_offset = padno % community->gpp_size;
@@ -821,6 +824,8 @@ static int intel_gpio_irq_wake(struct irq_data *d, unsigned int on)
                gpe_en &= ~BIT(gpp_offset);
        writel(gpe_en, community->regs + GPI_GPE_EN + gpp * 4);
 
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+
        dev_dbg(pctrl->dev, "%sable wake for pin %u\n", on ? "en" : "dis", pin);
        return 0;
 }
@@ -919,7 +924,8 @@ static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq)
         * to the irq directly) because on some platforms several GPIO
         * controllers share the same interrupt line.
         */
-       ret = devm_request_irq(pctrl->dev, irq, intel_gpio_irq, IRQF_SHARED,
+       ret = devm_request_irq(pctrl->dev, irq, intel_gpio_irq,
+                              IRQF_SHARED | IRQF_NO_THREAD,
                               dev_name(pctrl->dev), pctrl);
        if (ret) {
                dev_err(pctrl->dev, "failed to request interrupt\n");
@@ -995,7 +1001,7 @@ int intel_pinctrl_probe(struct platform_device *pdev,
 
        pctrl->dev = &pdev->dev;
        pctrl->soc = soc_data;
-       spin_lock_init(&pctrl->lock);
+       raw_spin_lock_init(&pctrl->lock);
 
        /*
         * Make a copy of the communities which we can use to hold pointers
diff --git a/drivers/pinctrl/intel/pinctrl-merrifield.c b/drivers/pinctrl/intel/pinctrl-merrifield.c
new file mode 100644 (file)
index 0000000..eb4990f
--- /dev/null
@@ -0,0 +1,911 @@
+/*
+ * Intel Merrifield SoC pinctrl driver
+ *
+ * Copyright (C) 2016, Intel Corporation
+ * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "pinctrl-intel.h"
+
+#define MRFLD_FAMILY_NR                        64
+#define MRFLD_FAMILY_LEN               0x400
+
+#define SLEW_OFFSET                    0x000
+#define BUFCFG_OFFSET                  0x100
+#define MISC_OFFSET                    0x300
+
+#define BUFCFG_PINMODE_SHIFT           0
+#define BUFCFG_PINMODE_MASK            GENMASK(2, 0)
+#define BUFCFG_PINMODE_GPIO            0
+#define BUFCFG_PUPD_VAL_SHIFT          4
+#define BUFCFG_PUPD_VAL_MASK           GENMASK(5, 4)
+#define BUFCFG_PUPD_VAL_2K             0
+#define BUFCFG_PUPD_VAL_20K            1
+#define BUFCFG_PUPD_VAL_50K            2
+#define BUFCFG_PUPD_VAL_910            3
+#define BUFCFG_PU_EN                   BIT(8)
+#define BUFCFG_PD_EN                   BIT(9)
+#define BUFCFG_Px_EN_MASK              GENMASK(9, 8)
+#define BUFCFG_SLEWSEL                 BIT(10)
+#define BUFCFG_OVINEN                  BIT(12)
+#define BUFCFG_OVINEN_EN               BIT(13)
+#define BUFCFG_OVINEN_MASK             GENMASK(13, 12)
+#define BUFCFG_OVOUTEN                 BIT(14)
+#define BUFCFG_OVOUTEN_EN              BIT(15)
+#define BUFCFG_OVOUTEN_MASK            GENMASK(15, 14)
+#define BUFCFG_INDATAOV_VAL            BIT(16)
+#define BUFCFG_INDATAOV_EN             BIT(17)
+#define BUFCFG_INDATAOV_MASK           GENMASK(17, 16)
+#define BUFCFG_OUTDATAOV_VAL           BIT(18)
+#define BUFCFG_OUTDATAOV_EN            BIT(19)
+#define BUFCFG_OUTDATAOV_MASK          GENMASK(19, 18)
+#define BUFCFG_OD_EN                   BIT(21)
+
+/**
+ * struct mrfld_family - Intel pin family description
+ * @barno: MMIO BAR number where registers for this family reside
+ * @pin_base: Starting pin of pins in this family
+ * @npins: Number of pins in this family
+ * @protected: True if family is protected by access
+ * @regs: family specific common registers
+ */
+struct mrfld_family {
+       unsigned int barno;
+       unsigned int pin_base;
+       size_t npins;
+       bool protected;
+       void __iomem *regs;
+};
+
+#define MRFLD_FAMILY(b, s, e)                          \
+       {                                               \
+               .barno = (b),                           \
+               .pin_base = (s),                        \
+               .npins = (e) - (s) + 1,                 \
+       }
+
+#define MRFLD_FAMILY_PROTECTED(b, s, e)                        \
+       {                                               \
+               .barno = (b),                           \
+               .pin_base = (s),                        \
+               .npins = (e) - (s) + 1,                 \
+               .protected = true,                      \
+       }
+
+static const struct pinctrl_pin_desc mrfld_pins[] = {
+       /* Family 0: OCP2SSC (0 pins) */
+       /* Family 1: ULPI (13 pins) */
+       PINCTRL_PIN(0, "ULPI_CLK"),
+       PINCTRL_PIN(1, "ULPI_D0"),
+       PINCTRL_PIN(2, "ULPI_D1"),
+       PINCTRL_PIN(3, "ULPI_D2"),
+       PINCTRL_PIN(4, "ULPI_D3"),
+       PINCTRL_PIN(5, "ULPI_D4"),
+       PINCTRL_PIN(6, "ULPI_D5"),
+       PINCTRL_PIN(7, "ULPI_D6"),
+       PINCTRL_PIN(8, "ULPI_D7"),
+       PINCTRL_PIN(9, "ULPI_DIR"),
+       PINCTRL_PIN(10, "ULPI_NXT"),
+       PINCTRL_PIN(11, "ULPI_REFCLK"),
+       PINCTRL_PIN(12, "ULPI_STP"),
+       /* Family 2: eMMC (24 pins) */
+       PINCTRL_PIN(13, "EMMC_CLK"),
+       PINCTRL_PIN(14, "EMMC_CMD"),
+       PINCTRL_PIN(15, "EMMC_D0"),
+       PINCTRL_PIN(16, "EMMC_D1"),
+       PINCTRL_PIN(17, "EMMC_D2"),
+       PINCTRL_PIN(18, "EMMC_D3"),
+       PINCTRL_PIN(19, "EMMC_D4"),
+       PINCTRL_PIN(20, "EMMC_D5"),
+       PINCTRL_PIN(21, "EMMC_D6"),
+       PINCTRL_PIN(22, "EMMC_D7"),
+       PINCTRL_PIN(23, "EMMC_RST_N"),
+       PINCTRL_PIN(24, "GP154"),
+       PINCTRL_PIN(25, "GP155"),
+       PINCTRL_PIN(26, "GP156"),
+       PINCTRL_PIN(27, "GP157"),
+       PINCTRL_PIN(28, "GP158"),
+       PINCTRL_PIN(29, "GP159"),
+       PINCTRL_PIN(30, "GP160"),
+       PINCTRL_PIN(31, "GP161"),
+       PINCTRL_PIN(32, "GP162"),
+       PINCTRL_PIN(33, "GP163"),
+       PINCTRL_PIN(34, "GP97"),
+       PINCTRL_PIN(35, "GP14"),
+       PINCTRL_PIN(36, "GP15"),
+       /* Family 3: SDIO (20 pins) */
+       PINCTRL_PIN(37, "GP77_SD_CD"),
+       PINCTRL_PIN(38, "GP78_SD_CLK"),
+       PINCTRL_PIN(39, "GP79_SD_CMD"),
+       PINCTRL_PIN(40, "GP80_SD_D0"),
+       PINCTRL_PIN(41, "GP81_SD_D1"),
+       PINCTRL_PIN(42, "GP82_SD_D2"),
+       PINCTRL_PIN(43, "GP83_SD_D3"),
+       PINCTRL_PIN(44, "GP84_SD_LS_CLK_FB"),
+       PINCTRL_PIN(45, "GP85_SD_LS_CMD_DIR"),
+       PINCTRL_PIN(46, "GP86_SD_LVL_D_DIR"),
+       PINCTRL_PIN(47, "GP88_SD_LS_SEL"),
+       PINCTRL_PIN(48, "GP87_SD_PD"),
+       PINCTRL_PIN(49, "GP89_SD_WP"),
+       PINCTRL_PIN(50, "GP90_SDIO_CLK"),
+       PINCTRL_PIN(51, "GP91_SDIO_CMD"),
+       PINCTRL_PIN(52, "GP92_SDIO_D0"),
+       PINCTRL_PIN(53, "GP93_SDIO_D1"),
+       PINCTRL_PIN(54, "GP94_SDIO_D2"),
+       PINCTRL_PIN(55, "GP95_SDIO_D3"),
+       PINCTRL_PIN(56, "GP96_SDIO_PD"),
+       /* Family 4: HSI (8 pins) */
+       PINCTRL_PIN(57, "HSI_ACDATA"),
+       PINCTRL_PIN(58, "HSI_ACFLAG"),
+       PINCTRL_PIN(59, "HSI_ACREADY"),
+       PINCTRL_PIN(60, "HSI_ACWAKE"),
+       PINCTRL_PIN(61, "HSI_CADATA"),
+       PINCTRL_PIN(62, "HSI_CAFLAG"),
+       PINCTRL_PIN(63, "HSI_CAREADY"),
+       PINCTRL_PIN(64, "HSI_CAWAKE"),
+       /* Family 5: SSP Audio (14 pins) */
+       PINCTRL_PIN(65, "GP70"),
+       PINCTRL_PIN(66, "GP71"),
+       PINCTRL_PIN(67, "GP32_I2S_0_CLK"),
+       PINCTRL_PIN(68, "GP33_I2S_0_FS"),
+       PINCTRL_PIN(69, "GP34_I2S_0_RXD"),
+       PINCTRL_PIN(70, "GP35_I2S_0_TXD"),
+       PINCTRL_PIN(71, "GP36_I2S_1_CLK"),
+       PINCTRL_PIN(72, "GP37_I2S_1_FS"),
+       PINCTRL_PIN(73, "GP38_I2S_1_RXD"),
+       PINCTRL_PIN(74, "GP39_I2S_1_TXD"),
+       PINCTRL_PIN(75, "GP40_I2S_2_CLK"),
+       PINCTRL_PIN(76, "GP41_I2S_2_FS"),
+       PINCTRL_PIN(77, "GP42_I2S_2_RXD"),
+       PINCTRL_PIN(78, "GP43_I2S_2_TXD"),
+       /* Family 6: GP SSP (22 pins) */
+       PINCTRL_PIN(79, "GP120_SPI_3_CLK"),
+       PINCTRL_PIN(80, "GP121_SPI_3_SS"),
+       PINCTRL_PIN(81, "GP122_SPI_3_RXD"),
+       PINCTRL_PIN(82, "GP123_SPI_3_TXD"),
+       PINCTRL_PIN(83, "GP102_SPI_4_CLK"),
+       PINCTRL_PIN(84, "GP103_SPI_4_SS_0"),
+       PINCTRL_PIN(85, "GP104_SPI_4_SS_1"),
+       PINCTRL_PIN(86, "GP105_SPI_4_SS_2"),
+       PINCTRL_PIN(87, "GP106_SPI_4_SS_3"),
+       PINCTRL_PIN(88, "GP107_SPI_4_RXD"),
+       PINCTRL_PIN(89, "GP108_SPI_4_TXD"),
+       PINCTRL_PIN(90, "GP109_SPI_5_CLK"),
+       PINCTRL_PIN(91, "GP110_SPI_5_SS_0"),
+       PINCTRL_PIN(92, "GP111_SPI_5_SS_1"),
+       PINCTRL_PIN(93, "GP112_SPI_5_SS_2"),
+       PINCTRL_PIN(94, "GP113_SPI_5_SS_3"),
+       PINCTRL_PIN(95, "GP114_SPI_5_RXD"),
+       PINCTRL_PIN(96, "GP115_SPI_5_TXD"),
+       PINCTRL_PIN(97, "GP116_SPI_6_CLK"),
+       PINCTRL_PIN(98, "GP117_SPI_6_SS"),
+       PINCTRL_PIN(99, "GP118_SPI_6_RXD"),
+       PINCTRL_PIN(100, "GP119_SPI_6_TXD"),
+       /* Family 7: I2C (14 pins) */
+       PINCTRL_PIN(101, "GP19_I2C_1_SCL"),
+       PINCTRL_PIN(102, "GP20_I2C_1_SDA"),
+       PINCTRL_PIN(103, "GP21_I2C_2_SCL"),
+       PINCTRL_PIN(104, "GP22_I2C_2_SDA"),
+       PINCTRL_PIN(105, "GP17_I2C_3_SCL_HDMI"),
+       PINCTRL_PIN(106, "GP18_I2C_3_SDA_HDMI"),
+       PINCTRL_PIN(107, "GP23_I2C_4_SCL"),
+       PINCTRL_PIN(108, "GP24_I2C_4_SDA"),
+       PINCTRL_PIN(109, "GP25_I2C_5_SCL"),
+       PINCTRL_PIN(110, "GP26_I2C_5_SDA"),
+       PINCTRL_PIN(111, "GP27_I2C_6_SCL"),
+       PINCTRL_PIN(112, "GP28_I2C_6_SDA"),
+       PINCTRL_PIN(113, "GP29_I2C_7_SCL"),
+       PINCTRL_PIN(114, "GP30_I2C_7_SDA"),
+       /* Family 8: UART (12 pins) */
+       PINCTRL_PIN(115, "GP124_UART_0_CTS"),
+       PINCTRL_PIN(116, "GP125_UART_0_RTS"),
+       PINCTRL_PIN(117, "GP126_UART_0_RX"),
+       PINCTRL_PIN(118, "GP127_UART_0_TX"),
+       PINCTRL_PIN(119, "GP128_UART_1_CTS"),
+       PINCTRL_PIN(120, "GP129_UART_1_RTS"),
+       PINCTRL_PIN(121, "GP130_UART_1_RX"),
+       PINCTRL_PIN(122, "GP131_UART_1_TX"),
+       PINCTRL_PIN(123, "GP132_UART_2_CTS"),
+       PINCTRL_PIN(124, "GP133_UART_2_RTS"),
+       PINCTRL_PIN(125, "GP134_UART_2_RX"),
+       PINCTRL_PIN(126, "GP135_UART_2_TX"),
+       /* Family 9: GPIO South (19 pins) */
+       PINCTRL_PIN(127, "GP177"),
+       PINCTRL_PIN(128, "GP178"),
+       PINCTRL_PIN(129, "GP179"),
+       PINCTRL_PIN(130, "GP180"),
+       PINCTRL_PIN(131, "GP181"),
+       PINCTRL_PIN(132, "GP182_PWM2"),
+       PINCTRL_PIN(133, "GP183_PWM3"),
+       PINCTRL_PIN(134, "GP184"),
+       PINCTRL_PIN(135, "GP185"),
+       PINCTRL_PIN(136, "GP186"),
+       PINCTRL_PIN(137, "GP187"),
+       PINCTRL_PIN(138, "GP188"),
+       PINCTRL_PIN(139, "GP189"),
+       PINCTRL_PIN(140, "GP64_FAST_INT0"),
+       PINCTRL_PIN(141, "GP65_FAST_INT1"),
+       PINCTRL_PIN(142, "GP66_FAST_INT2"),
+       PINCTRL_PIN(143, "GP67_FAST_INT3"),
+       PINCTRL_PIN(144, "GP12_PWM0"),
+       PINCTRL_PIN(145, "GP13_PWM1"),
+       /* Family 10: Camera Sideband (12 pins) */
+       PINCTRL_PIN(146, "GP0"),
+       PINCTRL_PIN(147, "GP1"),
+       PINCTRL_PIN(148, "GP2"),
+       PINCTRL_PIN(149, "GP3"),
+       PINCTRL_PIN(150, "GP4"),
+       PINCTRL_PIN(151, "GP5"),
+       PINCTRL_PIN(152, "GP6"),
+       PINCTRL_PIN(153, "GP7"),
+       PINCTRL_PIN(154, "GP8"),
+       PINCTRL_PIN(155, "GP9"),
+       PINCTRL_PIN(156, "GP10"),
+       PINCTRL_PIN(157, "GP11"),
+       /* Family 11: Clock (22 pins) */
+       PINCTRL_PIN(158, "GP137"),
+       PINCTRL_PIN(159, "GP138"),
+       PINCTRL_PIN(160, "GP139"),
+       PINCTRL_PIN(161, "GP140"),
+       PINCTRL_PIN(162, "GP141"),
+       PINCTRL_PIN(163, "GP142"),
+       PINCTRL_PIN(164, "GP16_HDMI_HPD"),
+       PINCTRL_PIN(165, "GP68_DSI_A_TE"),
+       PINCTRL_PIN(166, "GP69_DSI_C_TE"),
+       PINCTRL_PIN(167, "OSC_CLK_CTRL0"),
+       PINCTRL_PIN(168, "OSC_CLK_CTRL1"),
+       PINCTRL_PIN(169, "OSC_CLK0"),
+       PINCTRL_PIN(170, "OSC_CLK1"),
+       PINCTRL_PIN(171, "OSC_CLK2"),
+       PINCTRL_PIN(172, "OSC_CLK3"),
+       PINCTRL_PIN(173, "OSC_CLK4"),
+       PINCTRL_PIN(174, "RESETOUT"),
+       PINCTRL_PIN(175, "PMODE"),
+       PINCTRL_PIN(176, "PRDY"),
+       PINCTRL_PIN(177, "PREQ"),
+       PINCTRL_PIN(178, "GP190"),
+       PINCTRL_PIN(179, "GP191"),
+       /* Family 12: MSIC (15 pins) */
+       PINCTRL_PIN(180, "I2C_0_SCL"),
+       PINCTRL_PIN(181, "I2C_0_SDA"),
+       PINCTRL_PIN(182, "IERR"),
+       PINCTRL_PIN(183, "JTAG_TCK"),
+       PINCTRL_PIN(184, "JTAG_TDI"),
+       PINCTRL_PIN(185, "JTAG_TDO"),
+       PINCTRL_PIN(186, "JTAG_TMS"),
+       PINCTRL_PIN(187, "JTAG_TRST"),
+       PINCTRL_PIN(188, "PROCHOT"),
+       PINCTRL_PIN(189, "RTC_CLK"),
+       PINCTRL_PIN(190, "SVID_ALERT"),
+       PINCTRL_PIN(191, "SVID_CLK"),
+       PINCTRL_PIN(192, "SVID_D"),
+       PINCTRL_PIN(193, "THERMTRIP"),
+       PINCTRL_PIN(194, "STANDBY"),
+       /* Family 13: Keyboard (20 pins) */
+       PINCTRL_PIN(195, "GP44"),
+       PINCTRL_PIN(196, "GP45"),
+       PINCTRL_PIN(197, "GP46"),
+       PINCTRL_PIN(198, "GP47"),
+       PINCTRL_PIN(199, "GP48"),
+       PINCTRL_PIN(200, "GP49"),
+       PINCTRL_PIN(201, "GP50"),
+       PINCTRL_PIN(202, "GP51"),
+       PINCTRL_PIN(203, "GP52"),
+       PINCTRL_PIN(204, "GP53"),
+       PINCTRL_PIN(205, "GP54"),
+       PINCTRL_PIN(206, "GP55"),
+       PINCTRL_PIN(207, "GP56"),
+       PINCTRL_PIN(208, "GP57"),
+       PINCTRL_PIN(209, "GP58"),
+       PINCTRL_PIN(210, "GP59"),
+       PINCTRL_PIN(211, "GP60"),
+       PINCTRL_PIN(212, "GP61"),
+       PINCTRL_PIN(213, "GP62"),
+       PINCTRL_PIN(214, "GP63"),
+       /* Family 14: GPIO North (13 pins) */
+       PINCTRL_PIN(215, "GP164"),
+       PINCTRL_PIN(216, "GP165"),
+       PINCTRL_PIN(217, "GP166"),
+       PINCTRL_PIN(218, "GP167"),
+       PINCTRL_PIN(219, "GP168_MJTAG_TCK"),
+       PINCTRL_PIN(220, "GP169_MJTAG_TDI"),
+       PINCTRL_PIN(221, "GP170_MJTAG_TDO"),
+       PINCTRL_PIN(222, "GP171_MJTAG_TMS"),
+       PINCTRL_PIN(223, "GP172_MJTAG_TRST"),
+       PINCTRL_PIN(224, "GP173"),
+       PINCTRL_PIN(225, "GP174"),
+       PINCTRL_PIN(226, "GP175"),
+       PINCTRL_PIN(227, "GP176"),
+       /* Family 15: PTI (5 pins) */
+       PINCTRL_PIN(228, "GP72_PTI_CLK"),
+       PINCTRL_PIN(229, "GP73_PTI_D0"),
+       PINCTRL_PIN(230, "GP74_PTI_D1"),
+       PINCTRL_PIN(231, "GP75_PTI_D2"),
+       PINCTRL_PIN(232, "GP76_PTI_D3"),
+       /* Family 16: USB3 (0 pins) */
+       /* Family 17: HSIC (0 pins) */
+       /* Family 18: Broadcast (0 pins) */
+};
+
+static const unsigned int mrfld_sdio_pins[] = { 50, 51, 52, 53, 54, 55, 56 };
+static const unsigned int mrfld_spi5_pins[] = { 90, 91, 92, 93, 94, 95, 96 };
+static const unsigned int mrfld_uart0_pins[] = { 124, 125, 126, 127 };
+static const unsigned int mrfld_uart1_pins[] = { 128, 129, 130, 131 };
+static const unsigned int mrfld_uart2_pins[] = { 132, 133, 134, 135 };
+static const unsigned int mrfld_pwm0_pins[] = { 144 };
+static const unsigned int mrfld_pwm1_pins[] = { 145 };
+static const unsigned int mrfld_pwm2_pins[] = { 132 };
+static const unsigned int mrfld_pwm3_pins[] = { 133 };
+
+static const struct intel_pingroup mrfld_groups[] = {
+       PIN_GROUP("sdio_grp", mrfld_sdio_pins, 1),
+       PIN_GROUP("spi5_grp", mrfld_spi5_pins, 1),
+       PIN_GROUP("uart0_grp", mrfld_uart0_pins, 1),
+       PIN_GROUP("uart1_grp", mrfld_uart1_pins, 1),
+       PIN_GROUP("uart2_grp", mrfld_uart2_pins, 1),
+       PIN_GROUP("pwm0_grp", mrfld_pwm0_pins, 1),
+       PIN_GROUP("pwm1_grp", mrfld_pwm1_pins, 1),
+       PIN_GROUP("pwm2_grp", mrfld_pwm2_pins, 1),
+       PIN_GROUP("pwm3_grp", mrfld_pwm3_pins, 1),
+};
+
+static const char * const mrfld_sdio_groups[] = { "sdio_grp" };
+static const char * const mrfld_spi5_groups[] = { "spi5_grp" };
+static const char * const mrfld_uart0_groups[] = { "uart0_grp" };
+static const char * const mrfld_uart1_groups[] = { "uart1_grp" };
+static const char * const mrfld_uart2_groups[] = { "uart2_grp" };
+static const char * const mrfld_pwm0_groups[] = { "pwm0_grp" };
+static const char * const mrfld_pwm1_groups[] = { "pwm1_grp" };
+static const char * const mrfld_pwm2_groups[] = { "pwm2_grp" };
+static const char * const mrfld_pwm3_groups[] = { "pwm3_grp" };
+
+static const struct intel_function mrfld_functions[] = {
+       FUNCTION("sdio", mrfld_sdio_groups),
+       FUNCTION("spi5", mrfld_spi5_groups),
+       FUNCTION("uart0", mrfld_uart0_groups),
+       FUNCTION("uart1", mrfld_uart1_groups),
+       FUNCTION("uart2", mrfld_uart2_groups),
+       FUNCTION("pwm0", mrfld_pwm0_groups),
+       FUNCTION("pwm1", mrfld_pwm1_groups),
+       FUNCTION("pwm2", mrfld_pwm2_groups),
+       FUNCTION("pwm3", mrfld_pwm3_groups),
+};
+
+static const struct mrfld_family mrfld_families[] = {
+       MRFLD_FAMILY(1, 0, 12),
+       MRFLD_FAMILY(2, 13, 36),
+       MRFLD_FAMILY(3, 37, 56),
+       MRFLD_FAMILY(4, 57, 64),
+       MRFLD_FAMILY(5, 65, 78),
+       MRFLD_FAMILY(6, 79, 100),
+       MRFLD_FAMILY_PROTECTED(7, 101, 114),
+       MRFLD_FAMILY(8, 115, 126),
+       MRFLD_FAMILY(9, 127, 145),
+       MRFLD_FAMILY(10, 146, 157),
+       MRFLD_FAMILY(11, 158, 179),
+       MRFLD_FAMILY_PROTECTED(12, 180, 194),
+       MRFLD_FAMILY(13, 195, 214),
+       MRFLD_FAMILY(14, 215, 227),
+       MRFLD_FAMILY(15, 228, 232),
+};
+
+/**
+ * struct mrfld_pinctrl - Intel Merrifield pinctrl private structure
+ * @dev: Pointer to the device structure
+ * @lock: Lock to serialize register access
+ * @pctldesc: Pin controller description
+ * @pctldev: Pointer to the pin controller device
+ * @families: Array of families this pinctrl handles
+ * @nfamilies: Number of families in the array
+ * @functions: Array of functions
+ * @nfunctions: Number of functions in the array
+ * @groups: Array of pin groups
+ * @ngroups: Number of groups in the array
+ * @pins: Array of pins this pinctrl controls
+ * @npins: Number of pins in the array
+ */
+struct mrfld_pinctrl {
+       struct device *dev;
+       raw_spinlock_t lock;
+       struct pinctrl_desc pctldesc;
+       struct pinctrl_dev *pctldev;
+
+       /* Pin controller configuration */
+       const struct mrfld_family *families;
+       size_t nfamilies;
+       const struct intel_function *functions;
+       size_t nfunctions;
+       const struct intel_pingroup *groups;
+       size_t ngroups;
+       const struct pinctrl_pin_desc *pins;
+       size_t npins;
+};
+
+#define pin_to_bufno(f, p)             ((p) - (f)->pin_base)
+
+static const struct mrfld_family *mrfld_get_family(struct mrfld_pinctrl *mp,
+                                                  unsigned int pin)
+{
+       const struct mrfld_family *family;
+       unsigned int i;
+
+       for (i = 0; i < mp->nfamilies; i++) {
+               family = &mp->families[i];
+               if (pin >= family->pin_base &&
+                   pin < family->pin_base + family->npins)
+                       return family;
+       }
+
+       dev_warn(mp->dev, "failed to find family for pin %u\n", pin);
+       return NULL;
+}
+
+static bool mrfld_buf_available(struct mrfld_pinctrl *mp, unsigned int pin)
+{
+       const struct mrfld_family *family;
+
+       family = mrfld_get_family(mp, pin);
+       if (!family)
+               return false;
+
+       return !family->protected;
+}
+
+static void __iomem *mrfld_get_bufcfg(struct mrfld_pinctrl *mp, unsigned int pin)
+{
+       const struct mrfld_family *family;
+       unsigned int bufno;
+
+       family = mrfld_get_family(mp, pin);
+       if (!family)
+               return NULL;
+
+       bufno = pin_to_bufno(family, pin);
+       return family->regs + BUFCFG_OFFSET + bufno * 4;
+}
+
+static int mrfld_get_groups_count(struct pinctrl_dev *pctldev)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+
+       return mp->ngroups;
+}
+
+static const char *mrfld_get_group_name(struct pinctrl_dev *pctldev,
+                                       unsigned int group)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+
+       return mp->groups[group].name;
+}
+
+static int mrfld_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group,
+                               const unsigned int **pins, unsigned int *npins)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+
+       *pins = mp->groups[group].pins;
+       *npins = mp->groups[group].npins;
+       return 0;
+}
+
+static void mrfld_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+                              unsigned int pin)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+       void __iomem *bufcfg;
+       u32 value, mode;
+
+       if (!mrfld_buf_available(mp, pin)) {
+               seq_puts(s, "not available");
+               return;
+       }
+
+       bufcfg = mrfld_get_bufcfg(mp, pin);
+       value = readl(bufcfg);
+
+       mode = (value & BUFCFG_PINMODE_MASK) >> BUFCFG_PINMODE_SHIFT;
+       if (!mode)
+               seq_puts(s, "GPIO ");
+       else
+               seq_printf(s, "mode %d ", mode);
+
+       seq_printf(s, "0x%08x", value);
+}
+
+static const struct pinctrl_ops mrfld_pinctrl_ops = {
+       .get_groups_count = mrfld_get_groups_count,
+       .get_group_name = mrfld_get_group_name,
+       .get_group_pins = mrfld_get_group_pins,
+       .pin_dbg_show = mrfld_pin_dbg_show,
+};
+
+static int mrfld_get_functions_count(struct pinctrl_dev *pctldev)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+
+       return mp->nfunctions;
+}
+
+static const char *mrfld_get_function_name(struct pinctrl_dev *pctldev,
+                                          unsigned int function)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+
+       return mp->functions[function].name;
+}
+
+static int mrfld_get_function_groups(struct pinctrl_dev *pctldev,
+                                    unsigned int function,
+                                    const char * const **groups,
+                                    unsigned int * const ngroups)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+
+       *groups = mp->functions[function].groups;
+       *ngroups = mp->functions[function].ngroups;
+       return 0;
+}
+
+static void mrfld_update_bufcfg(struct mrfld_pinctrl *mp, unsigned int pin,
+                               u32 bits, u32 mask)
+{
+       void __iomem *bufcfg;
+       u32 value;
+
+       bufcfg = mrfld_get_bufcfg(mp, pin);
+       value = readl(bufcfg);
+
+       value &= ~mask;
+       value |= bits & mask;
+
+       writel(value, bufcfg);
+}
+
+static int mrfld_pinmux_set_mux(struct pinctrl_dev *pctldev,
+                               unsigned int function,
+                               unsigned int group)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+       const struct intel_pingroup *grp = &mp->groups[group];
+       u32 bits = grp->mode << BUFCFG_PINMODE_SHIFT;
+       u32 mask = BUFCFG_PINMODE_MASK;
+       unsigned long flags;
+       unsigned int i;
+
+       /*
+        * All pins in the groups needs to be accessible and writable
+        * before we can enable the mux for this group.
+        */
+       for (i = 0; i < grp->npins; i++) {
+               if (!mrfld_buf_available(mp, grp->pins[i]))
+                       return -EBUSY;
+       }
+
+       /* Now enable the mux setting for each pin in the group */
+       raw_spin_lock_irqsave(&mp->lock, flags);
+       for (i = 0; i < grp->npins; i++)
+               mrfld_update_bufcfg(mp, grp->pins[i], bits, mask);
+       raw_spin_unlock_irqrestore(&mp->lock, flags);
+
+       return 0;
+}
+
+static int mrfld_gpio_request_enable(struct pinctrl_dev *pctldev,
+                                    struct pinctrl_gpio_range *range,
+                                    unsigned int pin)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+       u32 bits = BUFCFG_PINMODE_GPIO << BUFCFG_PINMODE_SHIFT;
+       u32 mask = BUFCFG_PINMODE_MASK;
+       unsigned long flags;
+
+       if (!mrfld_buf_available(mp, pin))
+               return -EBUSY;
+
+       raw_spin_lock_irqsave(&mp->lock, flags);
+       mrfld_update_bufcfg(mp, pin, bits, mask);
+       raw_spin_unlock_irqrestore(&mp->lock, flags);
+
+       return 0;
+}
+
+static const struct pinmux_ops mrfld_pinmux_ops = {
+       .get_functions_count = mrfld_get_functions_count,
+       .get_function_name = mrfld_get_function_name,
+       .get_function_groups = mrfld_get_function_groups,
+       .set_mux = mrfld_pinmux_set_mux,
+       .gpio_request_enable = mrfld_gpio_request_enable,
+};
+
+static int mrfld_config_get(struct pinctrl_dev *pctldev, unsigned int pin,
+                           unsigned long *config)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+       enum pin_config_param param = pinconf_to_config_param(*config);
+       u32 value, term;
+       u16 arg = 0;
+
+       if (!mrfld_buf_available(mp, pin))
+               return -ENOTSUPP;
+
+       value = readl(mrfld_get_bufcfg(mp, pin));
+       term = (value & BUFCFG_PUPD_VAL_MASK) >> BUFCFG_PUPD_VAL_SHIFT;
+
+       switch (param) {
+       case PIN_CONFIG_BIAS_DISABLE:
+               if (value & BUFCFG_Px_EN_MASK)
+                       return -EINVAL;
+               break;
+
+       case PIN_CONFIG_BIAS_PULL_UP:
+               if ((value & BUFCFG_Px_EN_MASK) != BUFCFG_PU_EN)
+                       return -EINVAL;
+
+               switch (term) {
+               case BUFCFG_PUPD_VAL_910:
+                       arg = 910;
+                       break;
+               case BUFCFG_PUPD_VAL_2K:
+                       arg = 2000;
+                       break;
+               case BUFCFG_PUPD_VAL_20K:
+                       arg = 20000;
+                       break;
+               case BUFCFG_PUPD_VAL_50K:
+                       arg = 50000;
+                       break;
+               }
+
+               break;
+
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+               if ((value & BUFCFG_Px_EN_MASK) != BUFCFG_PD_EN)
+                       return -EINVAL;
+
+               switch (term) {
+               case BUFCFG_PUPD_VAL_910:
+                       arg = 910;
+                       break;
+               case BUFCFG_PUPD_VAL_2K:
+                       arg = 2000;
+                       break;
+               case BUFCFG_PUPD_VAL_20K:
+                       arg = 20000;
+                       break;
+               case BUFCFG_PUPD_VAL_50K:
+                       arg = 50000;
+                       break;
+               }
+
+               break;
+
+       case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+               if (!(value & BUFCFG_OD_EN))
+                       return -EINVAL;
+               break;
+
+       case PIN_CONFIG_SLEW_RATE:
+               if (!(value & BUFCFG_SLEWSEL))
+                       arg = 0;
+               else
+                       arg = 1;
+               break;
+
+       default:
+               return -ENOTSUPP;
+       }
+
+       *config = pinconf_to_config_packed(param, arg);
+       return 0;
+}
+
+static int mrfld_config_set_pin(struct mrfld_pinctrl *mp, unsigned int pin,
+                               unsigned long config)
+{
+       unsigned int param = pinconf_to_config_param(config);
+       unsigned int arg = pinconf_to_config_argument(config);
+       u32 bits = 0, mask = 0;
+       unsigned long flags;
+
+       switch (param) {
+       case PIN_CONFIG_BIAS_DISABLE:
+               mask |= BUFCFG_Px_EN_MASK | BUFCFG_PUPD_VAL_MASK;
+               break;
+
+       case PIN_CONFIG_BIAS_PULL_UP:
+               mask |= BUFCFG_Px_EN_MASK | BUFCFG_PUPD_VAL_MASK;
+               bits |= BUFCFG_PU_EN;
+
+               switch (arg) {
+               case 50000:
+                       bits |= BUFCFG_PUPD_VAL_50K << BUFCFG_PUPD_VAL_SHIFT;
+                       break;
+               case 20000:
+                       bits |= BUFCFG_PUPD_VAL_20K << BUFCFG_PUPD_VAL_SHIFT;
+                       break;
+               case 2000:
+                       bits |= BUFCFG_PUPD_VAL_2K << BUFCFG_PUPD_VAL_SHIFT;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               break;
+
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+               mask |= BUFCFG_Px_EN_MASK | BUFCFG_PUPD_VAL_MASK;
+               bits |= BUFCFG_PD_EN;
+
+               switch (arg) {
+               case 50000:
+                       bits |= BUFCFG_PUPD_VAL_50K << BUFCFG_PUPD_VAL_SHIFT;
+                       break;
+               case 20000:
+                       bits |= BUFCFG_PUPD_VAL_20K << BUFCFG_PUPD_VAL_SHIFT;
+                       break;
+               case 2000:
+                       bits |= BUFCFG_PUPD_VAL_2K << BUFCFG_PUPD_VAL_SHIFT;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               break;
+
+       case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+               mask |= BUFCFG_OD_EN;
+               if (arg)
+                       bits |= BUFCFG_OD_EN;
+               break;
+
+       case PIN_CONFIG_SLEW_RATE:
+               mask |= BUFCFG_SLEWSEL;
+               if (arg)
+                       bits |= BUFCFG_SLEWSEL;
+               break;
+       }
+
+       raw_spin_lock_irqsave(&mp->lock, flags);
+       mrfld_update_bufcfg(mp, pin, bits, mask);
+       raw_spin_unlock_irqrestore(&mp->lock, flags);
+
+       return 0;
+}
+
+static int mrfld_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
+                           unsigned long *configs, unsigned int nconfigs)
+{
+       struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < nconfigs; i++) {
+               switch (pinconf_to_config_param(configs[i])) {
+               case PIN_CONFIG_BIAS_DISABLE:
+               case PIN_CONFIG_BIAS_PULL_UP:
+               case PIN_CONFIG_BIAS_PULL_DOWN:
+               case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+               case PIN_CONFIG_SLEW_RATE:
+                       ret = mrfld_config_set_pin(mp, pin, configs[i]);
+                       if (ret)
+                               return ret;
+                       break;
+
+               default:
+                       return -ENOTSUPP;
+               }
+       }
+
+       return 0;
+}
+
+static const struct pinconf_ops mrfld_pinconf_ops = {
+       .is_generic = true,
+       .pin_config_get = mrfld_config_get,
+       .pin_config_set = mrfld_config_set,
+};
+
+static const struct pinctrl_desc mrfld_pinctrl_desc = {
+       .pctlops = &mrfld_pinctrl_ops,
+       .pmxops = &mrfld_pinmux_ops,
+       .confops = &mrfld_pinconf_ops,
+       .owner = THIS_MODULE,
+};
+
+static int mrfld_pinctrl_probe(struct platform_device *pdev)
+{
+       struct mrfld_family *families;
+       struct mrfld_pinctrl *mp;
+       struct resource *mem;
+       void __iomem *regs;
+       size_t nfamilies;
+       unsigned int i;
+
+       mp = devm_kzalloc(&pdev->dev, sizeof(*mp), GFP_KERNEL);
+       if (!mp)
+               return -ENOMEM;
+
+       mp->dev = &pdev->dev;
+       raw_spin_lock_init(&mp->lock);
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       regs = devm_ioremap_resource(&pdev->dev, mem);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+
+       /*
+        * Make a copy of the families which we can use to hold pointers
+        * to the registers.
+        */
+       nfamilies = ARRAY_SIZE(mrfld_families),
+       families = devm_kmemdup(&pdev->dev, mrfld_families,
+                                           nfamilies * sizeof(mrfld_families),
+                                           GFP_KERNEL);
+       if (!families)
+               return -ENOMEM;
+
+       /* Splice memory resource by chunk per family */
+       for (i = 0; i < nfamilies; i++) {
+               struct mrfld_family *family = &families[i];
+
+               family->regs = regs + family->barno * MRFLD_FAMILY_LEN;
+       }
+
+       mp->families = families;
+       mp->nfamilies = nfamilies;
+       mp->functions = mrfld_functions;
+       mp->nfunctions = ARRAY_SIZE(mrfld_functions);
+       mp->groups = mrfld_groups;
+       mp->ngroups = ARRAY_SIZE(mrfld_groups);
+       mp->pctldesc = mrfld_pinctrl_desc;
+       mp->pctldesc.name = dev_name(&pdev->dev);
+       mp->pctldesc.pins = mrfld_pins;
+       mp->pctldesc.npins = ARRAY_SIZE(mrfld_pins);
+
+       mp->pctldev = devm_pinctrl_register(&pdev->dev, &mp->pctldesc, mp);
+       if (IS_ERR(mp->pctldev)) {
+               dev_err(&pdev->dev, "failed to register pinctrl driver\n");
+               return PTR_ERR(mp->pctldev);
+       }
+
+       platform_set_drvdata(pdev, mp);
+       return 0;
+}
+
+static struct platform_driver mrfld_pinctrl_driver = {
+       .probe = mrfld_pinctrl_probe,
+       .driver = {
+               .name = "pinctrl-merrifield",
+       },
+};
+
+static int __init mrfld_pinctrl_init(void)
+{
+       return platform_driver_register(&mrfld_pinctrl_driver);
+}
+subsys_initcall(mrfld_pinctrl_init);
+
+static void __exit mrfld_pinctrl_exit(void)
+{
+       platform_driver_unregister(&mrfld_pinctrl_driver);
+}
+module_exit(mrfld_pinctrl_exit);
+
+MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
+MODULE_DESCRIPTION("Intel Merrifield SoC pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:pinctrl-merrifield");
index a607655..ce554e0 100644 (file)
@@ -1183,8 +1183,8 @@ static int mtk_eint_resume(struct device *device)
 }
 
 const struct dev_pm_ops mtk_eint_pm_ops = {
-       .suspend = mtk_eint_suspend,
-       .resume = mtk_eint_resume,
+       .suspend_noirq = mtk_eint_suspend,
+       .resume_noirq = mtk_eint_resume,
 };
 
 static void mtk_eint_ack(struct irq_data *d)
index eeabafb..cb4d6ad 100644 (file)
@@ -147,6 +147,52 @@ static const struct pinctrl_pin_desc meson_gxbb_periphs_pins[] = {
        MESON_PIN(GPIO_TEST_N, EE_OFF),
 };
 
+static const unsigned int emmc_nand_d07_pins[] = {
+       PIN(BOOT_0, EE_OFF), PIN(BOOT_1, EE_OFF), PIN(BOOT_2, EE_OFF),
+       PIN(BOOT_3, EE_OFF), PIN(BOOT_4, EE_OFF), PIN(BOOT_5, EE_OFF),
+       PIN(BOOT_6, EE_OFF), PIN(BOOT_7, EE_OFF),
+};
+static const unsigned int emmc_clk_pins[] = { PIN(BOOT_8, EE_OFF) };
+static const unsigned int emmc_cmd_pins[] = { PIN(BOOT_10, EE_OFF) };
+static const unsigned int emmc_ds_pins[] = { PIN(BOOT_15, EE_OFF) };
+
+static const unsigned int sdcard_d0_pins[] = { PIN(CARD_1, EE_OFF) };
+static const unsigned int sdcard_d1_pins[] = { PIN(CARD_0, EE_OFF) };
+static const unsigned int sdcard_d2_pins[] = { PIN(CARD_5, EE_OFF) };
+static const unsigned int sdcard_d3_pins[] = { PIN(CARD_4, EE_OFF) };
+static const unsigned int sdcard_cmd_pins[] = { PIN(CARD_3, EE_OFF) };
+static const unsigned int sdcard_clk_pins[] = { PIN(CARD_2, EE_OFF) };
+
+static const unsigned int uart_tx_a_pins[]     = { PIN(GPIOX_12, EE_OFF) };
+static const unsigned int uart_rx_a_pins[]     = { PIN(GPIOX_13, EE_OFF) };
+static const unsigned int uart_cts_a_pins[]    = { PIN(GPIOX_14, EE_OFF) };
+static const unsigned int uart_rts_a_pins[]    = { PIN(GPIOX_15, EE_OFF) };
+
+static const unsigned int uart_tx_b_pins[]     = { PIN(GPIODV_24, EE_OFF) };
+static const unsigned int uart_rx_b_pins[]     = { PIN(GPIODV_25, EE_OFF) };
+static const unsigned int uart_cts_b_pins[]    = { PIN(GPIODV_26, EE_OFF) };
+static const unsigned int uart_rts_b_pins[]    = { PIN(GPIODV_27, EE_OFF) };
+
+static const unsigned int uart_tx_c_pins[]     = { PIN(GPIOY_13, EE_OFF) };
+static const unsigned int uart_rx_c_pins[]     = { PIN(GPIOY_14, EE_OFF) };
+static const unsigned int uart_cts_c_pins[]    = { PIN(GPIOX_11, EE_OFF) };
+static const unsigned int uart_rts_c_pins[]    = { PIN(GPIOX_12, EE_OFF) };
+
+static const unsigned int eth_mdio_pins[]      = { PIN(GPIOZ_0, EE_OFF) };
+static const unsigned int eth_mdc_pins[]       = { PIN(GPIOZ_1, EE_OFF) };
+static const unsigned int eth_clk_rx_clk_pins[]        = { PIN(GPIOZ_2, EE_OFF) };
+static const unsigned int eth_rx_dv_pins[]     = { PIN(GPIOZ_3, EE_OFF) };
+static const unsigned int eth_rxd0_pins[]      = { PIN(GPIOZ_4, EE_OFF) };
+static const unsigned int eth_rxd1_pins[]      = { PIN(GPIOZ_5, EE_OFF) };
+static const unsigned int eth_rxd2_pins[]      = { PIN(GPIOZ_6, EE_OFF) };
+static const unsigned int eth_rxd3_pins[]      = { PIN(GPIOZ_7, EE_OFF) };
+static const unsigned int eth_rgmii_tx_clk_pins[] = { PIN(GPIOZ_8, EE_OFF) };
+static const unsigned int eth_tx_en_pins[]     = { PIN(GPIOZ_9, EE_OFF) };
+static const unsigned int eth_txd0_pins[]      = { PIN(GPIOZ_10, EE_OFF) };
+static const unsigned int eth_txd1_pins[]      = { PIN(GPIOZ_11, EE_OFF) };
+static const unsigned int eth_txd2_pins[]      = { PIN(GPIOZ_12, EE_OFF) };
+static const unsigned int eth_txd3_pins[]      = { PIN(GPIOZ_13, EE_OFF) };
+
 static const struct pinctrl_pin_desc meson_gxbb_aobus_pins[] = {
        MESON_PIN(GPIOAO_0, 0),
        MESON_PIN(GPIOAO_1, 0),
@@ -168,6 +214,16 @@ static const unsigned int uart_tx_ao_a_pins[]      = { PIN(GPIOAO_0, 0) };
 static const unsigned int uart_rx_ao_a_pins[]  = { PIN(GPIOAO_1, 0) };
 static const unsigned int uart_cts_ao_a_pins[] = { PIN(GPIOAO_2, 0) };
 static const unsigned int uart_rts_ao_a_pins[] = { PIN(GPIOAO_3, 0) };
+static const unsigned int uart_tx_ao_b_pins[]  = { PIN(GPIOAO_0, 0) };
+static const unsigned int uart_rx_ao_b_pins[]  = { PIN(GPIOAO_1, 0),
+                                                   PIN(GPIOAO_5, 0) };
+static const unsigned int uart_cts_ao_b_pins[] = { PIN(GPIOAO_2, 0) };
+static const unsigned int uart_rts_ao_b_pins[] = { PIN(GPIOAO_3, 0) };
+
+static const unsigned int i2c_sck_ao_pins[] = {PIN(GPIOAO_4, 0) };
+static const unsigned int i2c_sda_ao_pins[] = {PIN(GPIOAO_5, 0) };
+static const unsigned int i2c_slave_sck_ao_pins[] = {PIN(GPIOAO_4, 0) };
+static const unsigned int i2c_slave_sda_ao_pins[] = {PIN(GPIOAO_5, 0) };
 
 static struct meson_pmx_group meson_gxbb_periphs_groups[] = {
        GPIO_GROUP(GPIOZ_0, EE_OFF),
@@ -297,6 +353,54 @@ static struct meson_pmx_group meson_gxbb_periphs_groups[] = {
        GPIO_GROUP(GPIOCLK_3, EE_OFF),
 
        GPIO_GROUP(GPIO_TEST_N, EE_OFF),
+
+       /* Bank X */
+       GROUP(uart_tx_a,        4,      13),
+       GROUP(uart_rx_a,        4,      12),
+       GROUP(uart_cts_a,       4,      11),
+       GROUP(uart_rts_a,       4,      10),
+
+       /* Bank Y */
+       GROUP(uart_cts_c,       1,      19),
+       GROUP(uart_rts_c,       1,      18),
+       GROUP(uart_tx_c,        1,      17),
+       GROUP(uart_rx_c,        1,      16),
+
+       /* Bank Z */
+       GROUP(eth_mdio,         6,      1),
+       GROUP(eth_mdc,          6,      0),
+       GROUP(eth_clk_rx_clk,   6,      13),
+       GROUP(eth_rx_dv,        6,      12),
+       GROUP(eth_rxd0,         6,      11),
+       GROUP(eth_rxd1,         6,      10),
+       GROUP(eth_rxd2,         6,      9),
+       GROUP(eth_rxd3,         6,      8),
+       GROUP(eth_rgmii_tx_clk, 6,      7),
+       GROUP(eth_tx_en,        6,      6),
+       GROUP(eth_txd0,         6,      5),
+       GROUP(eth_txd1,         6,      4),
+       GROUP(eth_txd2,         6,      3),
+       GROUP(eth_txd3,         6,      2),
+
+       /* Bank DV */
+       GROUP(uart_tx_b,        2,      29),
+       GROUP(uart_rx_b,        2,      28),
+       GROUP(uart_cts_b,       2,      27),
+       GROUP(uart_rts_b,       2,      26),
+
+       /* Bank BOOT */
+       GROUP(emmc_nand_d07,    4,      30),
+       GROUP(emmc_clk,         4,      18),
+       GROUP(emmc_cmd,         4,      19),
+       GROUP(emmc_ds,          4,      31),
+
+       /* Bank CARD */
+       GROUP(sdcard_d1,        2,      14),
+       GROUP(sdcard_d0,        2,      15),
+       GROUP(sdcard_d3,        2,      12),
+       GROUP(sdcard_d2,        2,      13),
+       GROUP(sdcard_cmd,       2,      10),
+       GROUP(sdcard_clk,       2,      11),
 };
 
 static struct meson_pmx_group meson_gxbb_aobus_groups[] = {
@@ -316,10 +420,18 @@ static struct meson_pmx_group meson_gxbb_aobus_groups[] = {
        GPIO_GROUP(GPIOAO_13, 0),
 
        /* bank AO */
+       GROUP(uart_tx_ao_b,     0,      26),
+       GROUP(uart_rx_ao_b,     0,      25),
        GROUP(uart_tx_ao_a,     0,      12),
        GROUP(uart_rx_ao_a,     0,      11),
        GROUP(uart_cts_ao_a,    0,      10),
        GROUP(uart_rts_ao_a,    0,      9),
+       GROUP(uart_cts_ao_b,    0,      8),
+       GROUP(uart_rts_ao_b,    0,      7),
+       GROUP(i2c_sck_ao,       0,      6),
+       GROUP(i2c_sda_ao,       0,      5),
+       GROUP(i2c_slave_sck_ao, 0,      2),
+       GROUP(i2c_slave_sda_ao, 0,      1),
 };
 
 static const char * const gpio_periphs_groups[] = {
@@ -359,6 +471,34 @@ static const char * const gpio_periphs_groups[] = {
        "GPIO_TEST_N",
 };
 
+static const char * const emmc_groups[] = {
+       "emmc_nand_d07", "emmc_clk", "emmc_cmd", "emmc_ds",
+};
+
+static const char * const sdcard_groups[] = {
+       "sdcard_d0", "sdcard_d1", "sdcard_d2", "sdcard_d3",
+       "sdcard_cmd", "sdcard_clk",
+};
+
+static const char * const uart_a_groups[] = {
+       "uart_tx_a", "uart_rx_a", "uart_cts_a", "uart_rts_a",
+};
+
+static const char * const uart_b_groups[] = {
+       "uart_tx_b", "uart_rx_b", "uart_cts_b", "uart_rts_b",
+};
+
+static const char * const uart_c_groups[] = {
+       "uart_tx_c", "uart_rx_c", "uart_cts_c", "uart_rts_c",
+};
+
+static const char * const eth_groups[] = {
+       "eth_mdio", "eth_mdc", "eth_clk_rx_clk", "eth_rx_dv",
+       "eth_rxd0", "eth_rxd1", "eth_rxd2", "eth_rxd3",
+       "eth_rgmii_tx_clk", "eth_tx_en",
+       "eth_txd0", "eth_txd1", "eth_txd2", "eth_txd3",
+};
+
 static const char * const gpio_aobus_groups[] = {
        "GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3", "GPIOAO_4",
        "GPIOAO_5", "GPIOAO_6", "GPIOAO_7", "GPIOAO_8", "GPIOAO_9",
@@ -366,16 +506,37 @@ static const char * const gpio_aobus_groups[] = {
 };
 
 static const char * const uart_ao_groups[] = {
-       "uart_tx_ao_a", "uart_rx_ao_a", "uart_cts_ao_a", "uart_rts_ao_a"
+       "uart_tx_ao_a", "uart_rx_ao_a", "uart_cts_ao_a", "uart_rts_ao_a",
+};
+
+static const char * const uart_ao_b_groups[] = {
+       "uart_tx_ao_b", "uart_rx_ao_b", "uart_cts_ao_b", "uart_rts_ao_b",
+};
+
+static const char * const i2c_ao_groups[] = {
+       "i2c_sdk_ao", "i2c_sda_ao",
+};
+
+static const char * const i2c_slave_ao_groups[] = {
+       "i2c_slave_sdk_ao", "i2c_slave_sda_ao",
 };
 
 static struct meson_pmx_func meson_gxbb_periphs_functions[] = {
        FUNCTION(gpio_periphs),
+       FUNCTION(emmc),
+       FUNCTION(sdcard),
+       FUNCTION(uart_a),
+       FUNCTION(uart_b),
+       FUNCTION(uart_c),
+       FUNCTION(eth),
 };
 
 static struct meson_pmx_func meson_gxbb_aobus_functions[] = {
        FUNCTION(gpio_aobus),
        FUNCTION(uart_ao),
+       FUNCTION(uart_ao_b),
+       FUNCTION(i2c_ao),
+       FUNCTION(i2c_slave_ao),
 };
 
 static struct meson_bank meson_gxbb_periphs_banks[] = {
index a78e9a4..5f89c26 100644 (file)
@@ -168,87 +168,87 @@ static struct mvebu_mpp_mode mv88f6xxx_mpp_modes[] = {
                MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "nand", "io1",     V(1, 1, 1, 1, 1, 1))),
        MPP_MODE(20,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp0",       V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql",    V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "txd0",     V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x5, "sata1", "act",    V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d0",       V(0, 0, 0, 0, 1, 0)),
-               MPP_VAR_FUNCTION(0xc, "mii", "rxerr",    V(1, 0, 0, 0, 0, 0))),
+               MPP_VAR_FUNCTION(0xc, "mii", "rxerr",    V(0, 0, 0, 0, 0, 0))),
        MPP_MODE(21,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp1",       V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql",    V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "txd1",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(1, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 0, 0, 0, 0)),
                MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x5, "sata0", "act",    V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d1",       V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(22,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp2",       V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql",    V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "txd2",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(1, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 0, 0, 0, 0)),
                MPP_VAR_FUNCTION(0x4, "audio", "rmclk",  V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x5, "sata1", "prsnt",  V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d2",       V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(23,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp3",       V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql",    V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "txd3",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "rmclk",  V(1, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "rmclk",  V(0, 0, 0, 0, 0, 0)),
                MPP_VAR_FUNCTION(0x4, "audio", "bclk",   V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x5, "sata0", "prsnt",  V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d3",       V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(24,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp4",       V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0",  V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "rxd0",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "bclk",   V(1, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "bclk",   V(0, 0, 0, 0, 0, 0)),
                MPP_VAR_FUNCTION(0x4, "audio", "sdo",    V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d4",       V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(25,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp5",       V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck",  V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "rxd1",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "sdo",    V(1, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "sdo",    V(0, 0, 0, 0, 0, 0)),
                MPP_VAR_FUNCTION(0x4, "audio", "lrclk",  V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d5",       V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(26,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp6",       V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "rxd2",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "lrclk",  V(1, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "lrclk",  V(0, 0, 0, 0, 0, 0)),
                MPP_VAR_FUNCTION(0x4, "audio", "mclk",   V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d6",       V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(27,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp7",       V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "rxd3",     V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "mclk",   V(1, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "mclk",   V(0, 0, 0, 0, 0, 0)),
                MPP_VAR_FUNCTION(0x4, "audio", "sdi",    V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d7",       V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(28,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp8",       V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "int",      V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "col",      V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "sdi",    V(1, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "sdi",    V(0, 0, 0, 0, 0, 0)),
                MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d8",       V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(29,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp9",       V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "rst",      V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "txclk",    V(0, 1, 1, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(1, 0, 0, 0, 0, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 0, 0, 0, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d9",       V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(30,
                MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 0)),
@@ -280,65 +280,65 @@ static struct mvebu_mpp_mode mv88f6xxx_mpp_modes[] = {
                MPP_VAR_FUNCTION(0x5, "sata1", "act",    V(0, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d14",      V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(35,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql",    V(0, 0, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x3, "ge1", "rxerr",    V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x5, "sata0", "act",    V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d15",      V(0, 0, 0, 0, 1, 0)),
-               MPP_VAR_FUNCTION(0xc, "mii", "rxerr",    V(0, 1, 1, 1, 1, 0))),
+               MPP_VAR_FUNCTION(0xc, "mii", "rxerr",    V(1, 1, 1, 1, 1, 0))),
        MPP_MODE(36,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp0",       V(0, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1",  V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 0, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(1, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "twsi1", "sda",    V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(37,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp1",       V(0, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql",    V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 0, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(1, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "twsi1", "sck",    V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(38,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp2",       V(0, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql",    V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "rmclk",  V(0, 0, 0, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "rmclk",  V(1, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d18",      V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(39,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp3",       V(0, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0",  V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "bclk",   V(0, 0, 0, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "bclk",   V(1, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d19",      V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(40,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp4",       V(0, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck",  V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "sdo",    V(0, 0, 0, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "sdo",    V(1, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d20",      V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(41,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp5",       V(0, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "lrclk",  V(0, 0, 0, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "lrclk",  V(1, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d21",      V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(42,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp6",       V(0, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "mclk",   V(0, 0, 0, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "mclk",   V(1, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d22",      V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(43,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp7",       V(0, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "int",      V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "sdi",    V(0, 0, 0, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "sdi",    V(1, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "d23",      V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(44,
-               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 0, 0, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "ts", "mp8",       V(0, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0x2, "tdm", "rst",      V(0, 0, 0, 1, 1, 0)),
-               MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 0, 1, 1, 0)),
+               MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(1, 0, 0, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "clk",      V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(45,
                MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1, 1)),
@@ -371,11 +371,12 @@ static struct mvebu_mpp_mode mv88f6xxx_mpp_modes[] = {
 };
 
 static struct mvebu_mpp_ctrl mv88f6180_mpp_controls[] = {
-       MPP_FUNC_CTRL(0, 29, NULL, kirkwood_mpp_ctrl),
+       MPP_FUNC_CTRL(0, 44, NULL, kirkwood_mpp_ctrl),
 };
 
 static struct pinctrl_gpio_range mv88f6180_gpio_ranges[] = {
-       MPP_GPIO_RANGE(0, 0, 0, 30),
+       MPP_GPIO_RANGE(0,  0,  0, 20),
+       MPP_GPIO_RANGE(1, 35, 35, 10),
 };
 
 static struct mvebu_mpp_ctrl mv88f619x_mpp_controls[] = {
index 38facef..35f6218 100644 (file)
@@ -1033,102 +1033,6 @@ static inline void nmk_gpio_dbg_show_one(struct seq_file *s,
 #define nmk_gpio_dbg_show      NULL
 #endif
 
-void nmk_gpio_clocks_enable(void)
-{
-       int i;
-
-       for (i = 0; i < NUM_BANKS; i++) {
-               struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
-
-               if (!chip)
-                       continue;
-
-               clk_enable(chip->clk);
-       }
-}
-
-void nmk_gpio_clocks_disable(void)
-{
-       int i;
-
-       for (i = 0; i < NUM_BANKS; i++) {
-               struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
-
-               if (!chip)
-                       continue;
-
-               clk_disable(chip->clk);
-       }
-}
-
-/*
- * Called from the suspend/resume path to only keep the real wakeup interrupts
- * (those that have had set_irq_wake() called on them) as wakeup interrupts,
- * and not the rest of the interrupts which we needed to have as wakeups for
- * cpuidle.
- *
- * PM ops are not used since this needs to be done at the end, after all the
- * other drivers are done with their suspend callbacks.
- */
-void nmk_gpio_wakeups_suspend(void)
-{
-       int i;
-
-       for (i = 0; i < NUM_BANKS; i++) {
-               struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
-
-               if (!chip)
-                       break;
-
-               clk_enable(chip->clk);
-
-               writel(chip->rwimsc & chip->real_wake,
-                      chip->addr + NMK_GPIO_RWIMSC);
-               writel(chip->fwimsc & chip->real_wake,
-                      chip->addr + NMK_GPIO_FWIMSC);
-
-               clk_disable(chip->clk);
-       }
-}
-
-void nmk_gpio_wakeups_resume(void)
-{
-       int i;
-
-       for (i = 0; i < NUM_BANKS; i++) {
-               struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
-
-               if (!chip)
-                       break;
-
-               clk_enable(chip->clk);
-
-               writel(chip->rwimsc, chip->addr + NMK_GPIO_RWIMSC);
-               writel(chip->fwimsc, chip->addr + NMK_GPIO_FWIMSC);
-
-               clk_disable(chip->clk);
-       }
-}
-
-/*
- * Read the pull up/pull down status.
- * A bit set in 'pull_up' means that pull up
- * is selected if pull is enabled in PDIS register.
- * Note: only pull up/down set via this driver can
- * be detected due to HW limitations.
- */
-void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up)
-{
-       if (gpio_bank < NUM_BANKS) {
-               struct nmk_gpio_chip *chip = nmk_gpio_chips[gpio_bank];
-
-               if (!chip)
-                       return;
-
-               *pull_up = chip->pull_up;
-       }
-}
-
 /*
  * We will allocate memory for the state container using devm* allocators
  * binding to the first device reaching this point, it doesn't matter if
index d5bf9fa..5020ae5 100644 (file)
@@ -53,7 +53,7 @@ static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev,
                                     struct seq_file *s, const char *gname,
                                     unsigned pin,
                                     const struct pin_config_item *items,
-                                    int nitems)
+                                    int nitems, int *print_sep)
 {
        int i;
 
@@ -75,8 +75,10 @@ static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev,
                        seq_printf(s, "ERROR READING CONFIG SETTING %d ", i);
                        continue;
                }
-               /* Space between multiple configs */
-               seq_puts(s, " ");
+               /* comma between multiple configs */
+               if (*print_sep)
+                       seq_puts(s, ", ");
+               *print_sep = 1;
                seq_puts(s, items[i].display);
                /* Print unit if available */
                if (items[i].has_arg) {
@@ -105,19 +107,21 @@ void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev, struct seq_file *s,
                               const char *gname, unsigned pin)
 {
        const struct pinconf_ops *ops = pctldev->desc->confops;
+       int print_sep = 0;
 
        if (!ops->is_generic)
                return;
 
        /* generic parameters */
        pinconf_generic_dump_one(pctldev, s, gname, pin, conf_items,
-                                ARRAY_SIZE(conf_items));
+                                ARRAY_SIZE(conf_items), &print_sep);
        /* driver-specific parameters */
        if (pctldev->desc->num_custom_params &&
            pctldev->desc->custom_conf_items)
                pinconf_generic_dump_one(pctldev, s, gname, pin,
                                         pctldev->desc->custom_conf_items,
-                                        pctldev->desc->num_custom_params);
+                                        pctldev->desc->num_custom_params,
+                                        &print_sep);
 }
 
 void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
@@ -391,4 +395,12 @@ exit:
 }
 EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map);
 
+void pinconf_generic_dt_free_map(struct pinctrl_dev *pctldev,
+                                struct pinctrl_map *map,
+                                unsigned num_maps)
+{
+       pinctrl_utils_free_map(pctldev, map, num_maps);
+}
+EXPORT_SYMBOL_GPL(pinconf_generic_dt_free_map);
+
 #endif
index 4dd7722..799048f 100644 (file)
@@ -258,8 +258,7 @@ void pinconf_show_setting(struct seq_file *s,
        case PIN_MAP_TYPE_CONFIGS_PIN:
                desc = pin_desc_get(setting->pctldev,
                                    setting->data.configs.group_or_pin);
-               seq_printf(s, "pin %s (%d)",
-                          desc->name ? desc->name : "unnamed",
+               seq_printf(s, "pin %s (%d)", desc->name,
                           setting->data.configs.group_or_pin);
                break;
        case PIN_MAP_TYPE_CONFIGS_GROUP:
@@ -311,8 +310,7 @@ static int pinconf_pins_show(struct seq_file *s, void *what)
                if (desc == NULL)
                        continue;
 
-               seq_printf(s, "pin %d (%s):", pin,
-                          desc->name ? desc->name : "unnamed");
+               seq_printf(s, "pin %d (%s): ", pin, desc->name);
 
                pinconf_dump_pin(pctldev, s, pin);
 
@@ -349,7 +347,7 @@ static int pinconf_groups_show(struct seq_file *s, void *what)
        while (selector < ngroups) {
                const char *gname = pctlops->get_group_name(pctldev, selector);
 
-               seq_printf(s, "%u (%s):", selector, gname);
+               seq_printf(s, "%u (%s): ", selector, gname);
                pinconf_dump_group(pctldev, s, selector, gname);
                seq_printf(s, "\n");
 
index a025b40..28bbc1b 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pinctrl/pinconf.h>
@@ -421,8 +421,8 @@ static int atmel_pctl_get_group_pins(struct pinctrl_dev *pctldev,
        return 0;
 }
 
-struct atmel_group *atmel_pctl_find_group_by_pin(struct pinctrl_dev *pctldev,
-                                                unsigned pin)
+static struct atmel_group *
+atmel_pctl_find_group_by_pin(struct pinctrl_dev *pctldev, unsigned pin)
 {
        struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev);
        int i;
@@ -879,7 +879,6 @@ static const struct of_device_id atmel_pctrl_of_match[] = {
                /* sentinel */
        }
 };
-MODULE_DEVICE_TABLE(of, atmel_pctrl_of_match);
 
 static int atmel_pinctrl_probe(struct platform_device *pdev)
 {
@@ -1074,28 +1073,13 @@ clk_prepare_enable_error:
        return ret;
 }
 
-int atmel_pinctrl_remove(struct platform_device *pdev)
-{
-       struct atmel_pioctrl *atmel_pioctrl = platform_get_drvdata(pdev);
-
-       irq_domain_remove(atmel_pioctrl->irq_domain);
-       clk_disable_unprepare(atmel_pioctrl->clk);
-       gpiochip_remove(atmel_pioctrl->gpio_chip);
-
-       return 0;
-}
-
 static struct platform_driver atmel_pinctrl_driver = {
        .driver = {
                .name = "pinctrl-at91-pio4",
                .of_match_table = atmel_pctrl_of_match,
                .pm = &atmel_pctrl_pm_ops,
+               .suppress_bind_attrs = true,
        },
        .probe = atmel_pinctrl_probe,
-       .remove = atmel_pinctrl_remove,
 };
-module_platform_driver(atmel_pinctrl_driver);
-
-MODULE_AUTHOR(Ludovic Desroches <ludovic.desroches@atmel.com>);
-MODULE_DESCRIPTION("Atmel PIO4 pinctrl driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(atmel_pinctrl_driver);
index b7c0d6f..80daead 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_address.h>
@@ -189,7 +188,7 @@ struct at91_pinctrl {
        struct at91_pinctrl_mux_ops *ops;
 };
 
-static const inline struct at91_pin_group *at91_pinctrl_find_group_by_name(
+static inline const struct at91_pin_group *at91_pinctrl_find_group_by_name(
                                const struct at91_pinctrl *info,
                                const char *name)
 {
@@ -1818,13 +1817,3 @@ static int __init at91_pinctrl_init(void)
        return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
 }
 arch_initcall(at91_pinctrl_init);
-
-static void __exit at91_pinctrl_exit(void)
-{
-       platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
-}
-
-module_exit(at91_pinctrl_exit);
-MODULE_AUTHOR("Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>");
-MODULE_DESCRIPTION("Atmel AT91 pinctrl driver");
-MODULE_LICENSE("GPL v2");
index 30ee564..639a57e 100644 (file)
@@ -15,7 +15,7 @@
  * - Pin pad configuration (pull up/down, strength)
  */
 
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -335,27 +335,17 @@ static int dc_pinctrl_probe(struct platform_device *pdev)
        return dc_gpiochip_add(pmap, pdev->dev.of_node);
 }
 
-static int dc_pinctrl_remove(struct platform_device *pdev)
-{
-       struct dc_pinmap *pmap = platform_get_drvdata(pdev);
-
-       gpiochip_remove(&pmap->chip);
-
-       return 0;
-}
-
 static const struct of_device_id dc_pinctrl_ids[] = {
        { .compatible = "cnxt,cx92755-pinctrl" },
        { /* sentinel */ }
 };
-MODULE_DEVICE_TABLE(of, dc_pinctrl_ids);
 
 static struct platform_driver dc_pinctrl_driver = {
        .driver = {
                .name = DRIVER_NAME,
                .of_match_table = dc_pinctrl_ids,
+               .suppress_bind_attrs = true,
        },
        .probe = dc_pinctrl_probe,
-       .remove = dc_pinctrl_remove,
 };
-module_platform_driver(dc_pinctrl_driver);
+builtin_platform_driver(dc_pinctrl_driver);
index 8a931c7..e053f1f 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/bitops.h>
 #include <linux/clk.h>
 #include <linux/io.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -1365,31 +1365,17 @@ static int lpc18xx_scu_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int lpc18xx_scu_remove(struct platform_device *pdev)
-{
-       struct lpc18xx_scu_data *scu = platform_get_drvdata(pdev);
-
-       clk_disable_unprepare(scu->clk);
-
-       return 0;
-}
-
 static const struct of_device_id lpc18xx_scu_match[] = {
        { .compatible = "nxp,lpc1850-scu" },
        {},
 };
-MODULE_DEVICE_TABLE(of, lpc18xx_scu_match);
 
 static struct platform_driver lpc18xx_scu_driver = {
        .probe          = lpc18xx_scu_probe,
-       .remove         = lpc18xx_scu_remove,
        .driver = {
                .name           = "lpc18xx-scu",
                .of_match_table = lpc18xx_scu_match,
+               .suppress_bind_attrs = true,
        },
 };
-module_platform_driver(lpc18xx_scu_driver);
-
-MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
-MODULE_DESCRIPTION("Pinctrl driver for NXP LPC18xx/43xx SCU");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(lpc18xx_scu_driver);
diff --git a/drivers/pinctrl/pinctrl-max77620.c b/drivers/pinctrl/pinctrl-max77620.c
new file mode 100644 (file)
index 0000000..d9ff53e
--- /dev/null
@@ -0,0 +1,673 @@
+/*
+ * MAX77620 pin control driver.
+ *
+ * Copyright (c) 2016, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Author:
+ *     Chaitanya Bandi <bandik@nvidia.com>
+ *     Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/mfd/max77620.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "core.h"
+#include "pinconf.h"
+#include "pinctrl-utils.h"
+
+#define MAX77620_PIN_NUM 8
+
+enum max77620_pin_ppdrv {
+       MAX77620_PIN_UNCONFIG_DRV,
+       MAX77620_PIN_OD_DRV,
+       MAX77620_PIN_PP_DRV,
+};
+
+enum max77620_pinconf_param {
+       MAX77620_ACTIVE_FPS_SOURCE = PIN_CONFIG_END + 1,
+       MAX77620_ACTIVE_FPS_POWER_ON_SLOTS,
+       MAX77620_ACTIVE_FPS_POWER_DOWN_SLOTS,
+       MAX77620_SUSPEND_FPS_SOURCE,
+       MAX77620_SUSPEND_FPS_POWER_ON_SLOTS,
+       MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS,
+};
+
+struct max77620_pin_function {
+       const char *name;
+       const char * const *groups;
+       unsigned int ngroups;
+       int mux_option;
+};
+
+static const struct pinconf_generic_params max77620_cfg_params[] = {
+       {
+               .property = "maxim,active-fps-source",
+               .param = MAX77620_ACTIVE_FPS_SOURCE,
+       }, {
+               .property = "maxim,active-fps-power-up-slot",
+               .param = MAX77620_ACTIVE_FPS_POWER_ON_SLOTS,
+       }, {
+               .property = "maxim,active-fps-power-down-slot",
+               .param = MAX77620_ACTIVE_FPS_POWER_DOWN_SLOTS,
+       }, {
+               .property = "maxim,suspend-fps-source",
+               .param = MAX77620_SUSPEND_FPS_SOURCE,
+       }, {
+               .property = "maxim,suspend-fps-power-up-slot",
+               .param = MAX77620_SUSPEND_FPS_POWER_ON_SLOTS,
+       }, {
+               .property = "maxim,suspend-fps-power-down-slot",
+               .param = MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS,
+       },
+};
+
+enum max77620_alternate_pinmux_option {
+       MAX77620_PINMUX_GPIO                            = 0,
+       MAX77620_PINMUX_LOW_POWER_MODE_CONTROL_IN       = 1,
+       MAX77620_PINMUX_FLEXIBLE_POWER_SEQUENCER_OUT    = 2,
+       MAX77620_PINMUX_32K_OUT1                        = 3,
+       MAX77620_PINMUX_SD0_DYNAMIC_VOLTAGE_SCALING_IN  = 4,
+       MAX77620_PINMUX_SD1_DYNAMIC_VOLTAGE_SCALING_IN  = 5,
+       MAX77620_PINMUX_REFERENCE_OUT                   = 6,
+};
+
+struct max77620_pingroup {
+       const char *name;
+       const unsigned int pins[1];
+       unsigned int npins;
+       enum max77620_alternate_pinmux_option alt_option;
+};
+
+struct max77620_pin_info {
+       enum max77620_pin_ppdrv drv_type;
+       int pull_config;
+};
+
+struct max77620_fps_config {
+       int active_fps_src;
+       int active_power_up_slots;
+       int active_power_down_slots;
+       int suspend_fps_src;
+       int suspend_power_up_slots;
+       int suspend_power_down_slots;
+};
+
+struct max77620_pctrl_info {
+       struct device *dev;
+       struct pinctrl_dev *pctl;
+       struct regmap *rmap;
+       int pins_current_opt[MAX77620_GPIO_NR];
+       const struct max77620_pin_function *functions;
+       unsigned int num_functions;
+       const struct max77620_pingroup *pin_groups;
+       int num_pin_groups;
+       const struct pinctrl_pin_desc *pins;
+       unsigned int num_pins;
+       struct max77620_pin_info pin_info[MAX77620_PIN_NUM];
+       struct max77620_fps_config fps_config[MAX77620_PIN_NUM];
+};
+
+static const struct pinctrl_pin_desc max77620_pins_desc[] = {
+       PINCTRL_PIN(MAX77620_GPIO0, "gpio0"),
+       PINCTRL_PIN(MAX77620_GPIO1, "gpio1"),
+       PINCTRL_PIN(MAX77620_GPIO2, "gpio2"),
+       PINCTRL_PIN(MAX77620_GPIO3, "gpio3"),
+       PINCTRL_PIN(MAX77620_GPIO4, "gpio4"),
+       PINCTRL_PIN(MAX77620_GPIO5, "gpio5"),
+       PINCTRL_PIN(MAX77620_GPIO6, "gpio6"),
+       PINCTRL_PIN(MAX77620_GPIO7, "gpio7"),
+};
+
+static const char * const gpio_groups[] = {
+       "gpio0",
+       "gpio1",
+       "gpio2",
+       "gpio3",
+       "gpio4",
+       "gpio5",
+       "gpio6",
+       "gpio7",
+};
+
+#define FUNCTION_GROUP(fname, mux)                     \
+       {                                               \
+               .name = fname,                          \
+               .groups = gpio_groups,                  \
+               .ngroups = ARRAY_SIZE(gpio_groups),     \
+               .mux_option = MAX77620_PINMUX_##mux,    \
+       }
+
+static const struct max77620_pin_function max77620_pin_function[] = {
+       FUNCTION_GROUP("gpio", GPIO),
+       FUNCTION_GROUP("lpm-control-in", LOW_POWER_MODE_CONTROL_IN),
+       FUNCTION_GROUP("fps-out", FLEXIBLE_POWER_SEQUENCER_OUT),
+       FUNCTION_GROUP("32k-out1", 32K_OUT1),
+       FUNCTION_GROUP("sd0-dvs-in", SD0_DYNAMIC_VOLTAGE_SCALING_IN),
+       FUNCTION_GROUP("sd1-dvs-in", SD1_DYNAMIC_VOLTAGE_SCALING_IN),
+       FUNCTION_GROUP("reference-out", REFERENCE_OUT),
+};
+
+#define MAX77620_PINGROUP(pg_name, pin_id, option) \
+       {                                                               \
+               .name = #pg_name,                                       \
+               .pins = {MAX77620_##pin_id},                            \
+               .npins = 1,                                             \
+               .alt_option = MAX77620_PINMUX_##option,                 \
+       }
+
+static const struct max77620_pingroup max77620_pingroups[] = {
+       MAX77620_PINGROUP(gpio0, GPIO0, LOW_POWER_MODE_CONTROL_IN),
+       MAX77620_PINGROUP(gpio1, GPIO1, FLEXIBLE_POWER_SEQUENCER_OUT),
+       MAX77620_PINGROUP(gpio2, GPIO2, FLEXIBLE_POWER_SEQUENCER_OUT),
+       MAX77620_PINGROUP(gpio3, GPIO3, FLEXIBLE_POWER_SEQUENCER_OUT),
+       MAX77620_PINGROUP(gpio4, GPIO4, 32K_OUT1),
+       MAX77620_PINGROUP(gpio5, GPIO5, SD0_DYNAMIC_VOLTAGE_SCALING_IN),
+       MAX77620_PINGROUP(gpio6, GPIO6, SD1_DYNAMIC_VOLTAGE_SCALING_IN),
+       MAX77620_PINGROUP(gpio7, GPIO7, REFERENCE_OUT),
+};
+
+static int max77620_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+       struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev);
+
+       return mpci->num_pin_groups;
+}
+
+static const char *max77620_pinctrl_get_group_name(
+               struct pinctrl_dev *pctldev, unsigned int group)
+{
+       struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev);
+
+       return mpci->pin_groups[group].name;
+}
+
+static int max77620_pinctrl_get_group_pins(
+               struct pinctrl_dev *pctldev, unsigned int group,
+               const unsigned int **pins, unsigned int *num_pins)
+{
+       struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev);
+
+       *pins = mpci->pin_groups[group].pins;
+       *num_pins = mpci->pin_groups[group].npins;
+
+       return 0;
+}
+
+static const struct pinctrl_ops max77620_pinctrl_ops = {
+       .get_groups_count = max77620_pinctrl_get_groups_count,
+       .get_group_name = max77620_pinctrl_get_group_name,
+       .get_group_pins = max77620_pinctrl_get_group_pins,
+       .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
+       .dt_free_map = pinctrl_utils_free_map,
+};
+
+static int max77620_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+       struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev);
+
+       return mpci->num_functions;
+}
+
+static const char *max77620_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
+                                                 unsigned int function)
+{
+       struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev);
+
+       return mpci->functions[function].name;
+}
+
+static int max77620_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
+                                           unsigned int function,
+                                           const char * const **groups,
+                                           unsigned int * const num_groups)
+{
+       struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev);
+
+       *groups = mpci->functions[function].groups;
+       *num_groups = mpci->functions[function].ngroups;
+
+       return 0;
+}
+
+static int max77620_pinctrl_enable(struct pinctrl_dev *pctldev,
+                                  unsigned int function, unsigned int group)
+{
+       struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev);
+       u8 val;
+       int ret;
+
+       if (function == MAX77620_PINMUX_GPIO) {
+               val = 0;
+       } else if (function == mpci->pin_groups[group].alt_option) {
+               val = 1 << group;
+       } else {
+               dev_err(mpci->dev, "GPIO %u doesn't have function %u\n",
+                       group, function);
+               return -EINVAL;
+       }
+       ret = regmap_update_bits(mpci->rmap, MAX77620_REG_AME_GPIO,
+                                BIT(group), val);
+       if (ret < 0)
+               dev_err(mpci->dev, "REG AME GPIO update failed: %d\n", ret);
+
+       return ret;
+}
+
+static const struct pinmux_ops max77620_pinmux_ops = {
+       .get_functions_count    = max77620_pinctrl_get_funcs_count,
+       .get_function_name      = max77620_pinctrl_get_func_name,
+       .get_function_groups    = max77620_pinctrl_get_func_groups,
+       .set_mux                = max77620_pinctrl_enable,
+};
+
+static int max77620_pinconf_get(struct pinctrl_dev *pctldev,
+                               unsigned int pin, unsigned long *config)
+{
+       struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev);
+       struct device *dev = mpci->dev;
+       enum pin_config_param param = pinconf_to_config_param(*config);
+       unsigned int val;
+       int arg = 0;
+       int ret;
+
+       switch (param) {
+       case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+               if (mpci->pin_info[pin].drv_type == MAX77620_PIN_OD_DRV)
+                       arg = 1;
+               break;
+
+       case PIN_CONFIG_DRIVE_PUSH_PULL:
+               if (mpci->pin_info[pin].drv_type == MAX77620_PIN_PP_DRV)
+                       arg = 1;
+               break;
+
+       case PIN_CONFIG_BIAS_PULL_UP:
+               ret = regmap_read(mpci->rmap, MAX77620_REG_PUE_GPIO, &val);
+               if (ret < 0) {
+                       dev_err(dev, "Reg PUE_GPIO read failed: %d\n", ret);
+                       return ret;
+               }
+               if (val & BIT(pin))
+                       arg = 1;
+               break;
+
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+               ret = regmap_read(mpci->rmap, MAX77620_REG_PDE_GPIO, &val);
+               if (ret < 0) {
+                       dev_err(dev, "Reg PDE_GPIO read failed: %d\n", ret);
+                       return ret;
+               }
+               if (val & BIT(pin))
+                       arg = 1;
+               break;
+
+       default:
+               dev_err(dev, "Properties not supported\n");
+               return -ENOTSUPP;
+       }
+
+       *config = pinconf_to_config_packed(param, (u16)arg);
+
+       return 0;
+}
+
+static int max77620_get_default_fps(struct max77620_pctrl_info *mpci,
+                                   int addr, int *fps)
+{
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(mpci->rmap, addr, &val);
+       if (ret < 0) {
+               dev_err(mpci->dev, "Reg PUE_GPIO read failed: %d\n", ret);
+               return ret;
+       }
+       *fps = (val & MAX77620_FPS_SRC_MASK) >> MAX77620_FPS_SRC_SHIFT;
+
+       return 0;
+}
+
+static int max77620_set_fps_param(struct max77620_pctrl_info *mpci,
+                                 int pin, int param)
+{
+       struct max77620_fps_config *fps_config = &mpci->fps_config[pin];
+       int addr, ret;
+       int param_val;
+       int mask, shift;
+
+       if ((pin < MAX77620_GPIO1) || (pin > MAX77620_GPIO3))
+               return 0;
+
+       addr = MAX77620_REG_FPS_GPIO1 + pin - 1;
+       switch (param) {
+       case MAX77620_ACTIVE_FPS_SOURCE:
+       case MAX77620_SUSPEND_FPS_SOURCE:
+               mask = MAX77620_FPS_SRC_MASK;
+               shift = MAX77620_FPS_SRC_SHIFT;
+               param_val = fps_config->active_fps_src;
+               if (param == MAX77620_SUSPEND_FPS_SOURCE)
+                       param_val = fps_config->suspend_fps_src;
+               break;
+
+       case MAX77620_ACTIVE_FPS_POWER_ON_SLOTS:
+       case MAX77620_SUSPEND_FPS_POWER_ON_SLOTS:
+               mask = MAX77620_FPS_PU_PERIOD_MASK;
+               shift = MAX77620_FPS_PU_PERIOD_SHIFT;
+               param_val = fps_config->active_power_up_slots;
+               if (param == MAX77620_SUSPEND_FPS_POWER_ON_SLOTS)
+                       param_val = fps_config->suspend_power_up_slots;
+               break;
+
+       case MAX77620_ACTIVE_FPS_POWER_DOWN_SLOTS:
+       case MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS:
+               mask = MAX77620_FPS_PD_PERIOD_MASK;
+               shift = MAX77620_FPS_PD_PERIOD_SHIFT;
+               param_val = fps_config->active_power_down_slots;
+               if (param == MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS)
+                       param_val = fps_config->suspend_power_down_slots;
+               break;
+
+       default:
+               dev_err(mpci->dev, "Invalid parameter %d for pin %d\n",
+                       param, pin);
+               return -EINVAL;
+       }
+
+       if (param_val < 0)
+               return 0;
+
+       ret = regmap_update_bits(mpci->rmap, addr, mask, param_val << shift);
+       if (ret < 0)
+               dev_err(mpci->dev, "Reg 0x%02x update failed %d\n", addr, ret);
+
+       return ret;
+}
+
+static int max77620_pinconf_set(struct pinctrl_dev *pctldev,
+                               unsigned int pin, unsigned long *configs,
+                               unsigned int num_configs)
+{
+       struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev);
+       struct device *dev = mpci->dev;
+       struct max77620_fps_config *fps_config;
+       int param;
+       u16 param_val;
+       unsigned int val;
+       unsigned int pu_val;
+       unsigned int pd_val;
+       int addr, ret;
+       int i;
+
+       for (i = 0; i < num_configs; i++) {
+               param = pinconf_to_config_param(configs[i]);
+               param_val = pinconf_to_config_argument(configs[i]);
+
+               switch (param) {
+               case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+                       val = param_val ? 0 : 1;
+                       ret = regmap_update_bits(mpci->rmap,
+                                                MAX77620_REG_GPIO0 + pin,
+                                                MAX77620_CNFG_GPIO_DRV_MASK,
+                                                val);
+                       if (ret < 0) {
+                               dev_err(dev, "Reg 0x%02x update failed %d\n",
+                                       MAX77620_REG_GPIO0 + pin, ret);
+                               return ret;
+                       }
+                       mpci->pin_info[pin].drv_type = val ?
+                               MAX77620_PIN_PP_DRV : MAX77620_PIN_OD_DRV;
+                       break;
+
+               case PIN_CONFIG_DRIVE_PUSH_PULL:
+                       val = param_val ? 1 : 0;
+                       ret = regmap_update_bits(mpci->rmap,
+                                                MAX77620_REG_GPIO0 + pin,
+                                                MAX77620_CNFG_GPIO_DRV_MASK,
+                                                val);
+                       if (ret < 0) {
+                               dev_err(dev, "Reg 0x%02x update failed %d\n",
+                                       MAX77620_REG_GPIO0 + pin, ret);
+                               return ret;
+                       }
+                       mpci->pin_info[pin].drv_type = val ?
+                               MAX77620_PIN_PP_DRV : MAX77620_PIN_OD_DRV;
+                       break;
+
+               case MAX77620_ACTIVE_FPS_SOURCE:
+               case MAX77620_ACTIVE_FPS_POWER_ON_SLOTS:
+               case MAX77620_ACTIVE_FPS_POWER_DOWN_SLOTS:
+                       if ((pin < MAX77620_GPIO1) || (pin > MAX77620_GPIO3))
+                               return -EINVAL;
+
+                       fps_config = &mpci->fps_config[pin];
+
+                       if ((param == MAX77620_ACTIVE_FPS_SOURCE) &&
+                           (param_val == MAX77620_FPS_SRC_DEF)) {
+                               addr = MAX77620_REG_FPS_GPIO1 + pin - 1;
+                               ret = max77620_get_default_fps(
+                                               mpci, addr,
+                                               &fps_config->active_fps_src);
+                               if (ret < 0)
+                                       return ret;
+                               break;
+                       }
+
+                       if (param == MAX77620_ACTIVE_FPS_SOURCE)
+                               fps_config->active_fps_src = param_val;
+                       else if (param == MAX77620_ACTIVE_FPS_POWER_ON_SLOTS)
+                               fps_config->active_power_up_slots = param_val;
+                       else
+                               fps_config->active_power_down_slots = param_val;
+
+                       ret = max77620_set_fps_param(mpci, pin, param);
+                       if (ret < 0)
+                               return ret;
+                       break;
+
+               case MAX77620_SUSPEND_FPS_SOURCE:
+               case MAX77620_SUSPEND_FPS_POWER_ON_SLOTS:
+               case MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS:
+                       if ((pin < MAX77620_GPIO1) || (pin > MAX77620_GPIO3))
+                               return -EINVAL;
+
+                       fps_config = &mpci->fps_config[pin];
+
+                       if ((param == MAX77620_SUSPEND_FPS_SOURCE) &&
+                           (param_val == MAX77620_FPS_SRC_DEF)) {
+                               addr = MAX77620_REG_FPS_GPIO1 + pin - 1;
+                               ret = max77620_get_default_fps(
+                                               mpci, addr,
+                                               &fps_config->suspend_fps_src);
+                               if (ret < 0)
+                                       return ret;
+                               break;
+                       }
+
+                       if (param == MAX77620_SUSPEND_FPS_SOURCE)
+                               fps_config->suspend_fps_src = param_val;
+                       else if (param == MAX77620_SUSPEND_FPS_POWER_ON_SLOTS)
+                               fps_config->suspend_power_up_slots = param_val;
+                       else
+                               fps_config->suspend_power_down_slots =
+                                                               param_val;
+                       break;
+
+               case PIN_CONFIG_BIAS_PULL_UP:
+               case PIN_CONFIG_BIAS_PULL_DOWN:
+                       pu_val = (param == PIN_CONFIG_BIAS_PULL_UP) ?
+                                                       BIT(pin) : 0;
+                       pd_val = (param == PIN_CONFIG_BIAS_PULL_DOWN) ?
+                                                       BIT(pin) : 0;
+
+                       ret = regmap_update_bits(mpci->rmap,
+                                                MAX77620_REG_PUE_GPIO,
+                                                BIT(pin), pu_val);
+                       if (ret < 0) {
+                               dev_err(dev, "PUE_GPIO update failed: %d\n",
+                                       ret);
+                               return ret;
+                       }
+
+                       ret = regmap_update_bits(mpci->rmap,
+                                                MAX77620_REG_PDE_GPIO,
+                                                BIT(pin), pd_val);
+                       if (ret < 0) {
+                               dev_err(dev, "PDE_GPIO update failed: %d\n",
+                                       ret);
+                               return ret;
+                       }
+                       break;
+
+               default:
+                       dev_err(dev, "Properties not supported\n");
+                       return -ENOTSUPP;
+               }
+       }
+
+       return 0;
+}
+
+static const struct pinconf_ops max77620_pinconf_ops = {
+       .pin_config_get = max77620_pinconf_get,
+       .pin_config_set = max77620_pinconf_set,
+};
+
+static struct pinctrl_desc max77620_pinctrl_desc = {
+       .pctlops = &max77620_pinctrl_ops,
+       .pmxops = &max77620_pinmux_ops,
+       .confops = &max77620_pinconf_ops,
+};
+
+static int max77620_pinctrl_probe(struct platform_device *pdev)
+{
+       struct max77620_chip *max77620 = dev_get_drvdata(pdev->dev.parent);
+       struct max77620_pctrl_info *mpci;
+       int i;
+
+       mpci = devm_kzalloc(&pdev->dev, sizeof(*mpci), GFP_KERNEL);
+       if (!mpci)
+               return -ENOMEM;
+
+       mpci->dev = &pdev->dev;
+       mpci->dev->of_node = pdev->dev.parent->of_node;
+       mpci->rmap = max77620->rmap;
+
+       mpci->pins = max77620_pins_desc;
+       mpci->num_pins = ARRAY_SIZE(max77620_pins_desc);
+       mpci->functions = max77620_pin_function;
+       mpci->num_functions = ARRAY_SIZE(max77620_pin_function);
+       mpci->pin_groups = max77620_pingroups;
+       mpci->num_pin_groups = ARRAY_SIZE(max77620_pingroups);
+       platform_set_drvdata(pdev, mpci);
+
+       max77620_pinctrl_desc.name = dev_name(&pdev->dev);
+       max77620_pinctrl_desc.pins = max77620_pins_desc;
+       max77620_pinctrl_desc.npins = ARRAY_SIZE(max77620_pins_desc);
+       max77620_pinctrl_desc.num_custom_params =
+                               ARRAY_SIZE(max77620_cfg_params);
+       max77620_pinctrl_desc.custom_params = max77620_cfg_params;
+
+       for (i = 0; i < MAX77620_PIN_NUM; ++i) {
+               mpci->fps_config[i].active_fps_src = -1;
+               mpci->fps_config[i].active_power_up_slots = -1;
+               mpci->fps_config[i].active_power_down_slots = -1;
+               mpci->fps_config[i].suspend_fps_src = -1;
+               mpci->fps_config[i].suspend_power_up_slots = -1;
+               mpci->fps_config[i].suspend_power_down_slots = -1;
+       }
+
+       mpci->pctl = devm_pinctrl_register(&pdev->dev, &max77620_pinctrl_desc,
+                                          mpci);
+       if (IS_ERR(mpci->pctl)) {
+               dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
+               return PTR_ERR(mpci->pctl);
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int max77620_suspend_fps_param[] = {
+       MAX77620_SUSPEND_FPS_SOURCE,
+       MAX77620_SUSPEND_FPS_POWER_ON_SLOTS,
+       MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS,
+};
+
+static int max77620_active_fps_param[] = {
+       MAX77620_ACTIVE_FPS_SOURCE,
+       MAX77620_ACTIVE_FPS_POWER_ON_SLOTS,
+       MAX77620_ACTIVE_FPS_POWER_DOWN_SLOTS,
+};
+
+static int max77620_pinctrl_suspend(struct device *dev)
+{
+       struct max77620_pctrl_info *mpci = dev_get_drvdata(dev);
+       int pin, p;
+
+       for (pin = 0; pin < MAX77620_PIN_NUM; ++pin) {
+               if ((pin < MAX77620_GPIO1) || (pin > MAX77620_GPIO3))
+                       continue;
+               for (p = 0; p < 3; ++p)
+                       max77620_set_fps_param(
+                               mpci, pin, max77620_suspend_fps_param[p]);
+       }
+
+       return 0;
+};
+
+static int max77620_pinctrl_resume(struct device *dev)
+{
+       struct max77620_pctrl_info *mpci = dev_get_drvdata(dev);
+       int pin, p;
+
+       for (pin = 0; pin < MAX77620_PIN_NUM; ++pin) {
+               if ((pin < MAX77620_GPIO1) || (pin > MAX77620_GPIO3))
+                       continue;
+               for (p = 0; p < 3; ++p)
+                       max77620_set_fps_param(
+                               mpci, pin, max77620_active_fps_param[p]);
+       }
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops max77620_pinctrl_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(
+               max77620_pinctrl_suspend, max77620_pinctrl_resume)
+};
+
+static const struct platform_device_id max77620_pinctrl_devtype[] = {
+       { .name = "max77620-pinctrl", },
+       { .name = "max20024-pinctrl", },
+       {},
+};
+MODULE_DEVICE_TABLE(platform, max77620_pinctrl_devtype);
+
+static struct platform_driver max77620_pinctrl_driver = {
+       .driver = {
+               .name = "max77620-pinctrl",
+               .pm = &max77620_pinctrl_pm_ops,
+       },
+       .probe = max77620_pinctrl_probe,
+       .id_table = max77620_pinctrl_devtype,
+};
+
+module_platform_driver(max77620_pinctrl_driver);
+
+MODULE_DESCRIPTION("MAX77620/MAX20024 pin control driver");
+MODULE_AUTHOR("Chaitanya Bandi<bandik@nvidia.com>");
+MODULE_AUTHOR("Laxman Dewangan<ldewangan@nvidia.com>");
+MODULE_ALIAS("platform:max77620-pinctrl");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-oxnas.c b/drivers/pinctrl/pinctrl-oxnas.c
new file mode 100644 (file)
index 0000000..917a7d2
--- /dev/null
@@ -0,0 +1,846 @@
+/*
+ * Oxford Semiconductor OXNAS SoC Family pinctrl driver
+ *
+ * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Based on pinctrl-pic32.c
+ * Joshua Henderson, <joshua.henderson@microchip.com>
+ * Copyright (C) 2015 Microchip Technology Inc.  All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#include "pinctrl-utils.h"
+
+#define PINS_PER_BANK          32
+
+#define GPIO_BANK_START(bank)          ((bank) * PINS_PER_BANK)
+
+/* Regmap Offsets */
+#define PINMUX_PRIMARY_SEL0    0x0c
+#define PINMUX_SECONDARY_SEL0  0x14
+#define PINMUX_TERTIARY_SEL0   0x8c
+#define PINMUX_PRIMARY_SEL1    0x10
+#define PINMUX_SECONDARY_SEL1  0x18
+#define PINMUX_TERTIARY_SEL1   0x90
+#define PINMUX_PULLUP_CTRL0    0xac
+#define PINMUX_PULLUP_CTRL1    0xb0
+
+/* GPIO Registers */
+#define INPUT_VALUE    0x00
+#define OUTPUT_EN      0x04
+#define IRQ_PENDING    0x0c
+#define OUTPUT_SET     0x14
+#define OUTPUT_CLEAR   0x18
+#define OUTPUT_EN_SET  0x1c
+#define OUTPUT_EN_CLEAR        0x20
+#define RE_IRQ_ENABLE  0x28
+#define FE_IRQ_ENABLE  0x2c
+
+struct oxnas_function {
+       const char *name;
+       const char * const *groups;
+       unsigned int ngroups;
+};
+
+struct oxnas_pin_group {
+       const char *name;
+       unsigned int pin;
+       unsigned int bank;
+       struct oxnas_desc_function *functions;
+};
+
+struct oxnas_desc_function {
+       const char *name;
+       unsigned int fct;
+};
+
+struct oxnas_gpio_bank {
+       void __iomem *reg_base;
+       struct gpio_chip gpio_chip;
+       struct irq_chip irq_chip;
+       unsigned int id;
+};
+
+struct oxnas_pinctrl {
+       struct regmap *regmap;
+       struct device *dev;
+       struct pinctrl_dev *pctldev;
+       const struct pinctrl_pin_desc *pins;
+       unsigned int npins;
+       const struct oxnas_function *functions;
+       unsigned int nfunctions;
+       const struct oxnas_pin_group *groups;
+       unsigned int ngroups;
+       struct oxnas_gpio_bank *gpio_banks;
+       unsigned int nbanks;
+};
+
+static const struct pinctrl_pin_desc oxnas_pins[] = {
+       PINCTRL_PIN(0, "gpio0"),
+       PINCTRL_PIN(1, "gpio1"),
+       PINCTRL_PIN(2, "gpio2"),
+       PINCTRL_PIN(3, "gpio3"),
+       PINCTRL_PIN(4, "gpio4"),
+       PINCTRL_PIN(5, "gpio5"),
+       PINCTRL_PIN(6, "gpio6"),
+       PINCTRL_PIN(7, "gpio7"),
+       PINCTRL_PIN(8, "gpio8"),
+       PINCTRL_PIN(9, "gpio9"),
+       PINCTRL_PIN(10, "gpio10"),
+       PINCTRL_PIN(11, "gpio11"),
+       PINCTRL_PIN(12, "gpio12"),
+       PINCTRL_PIN(13, "gpio13"),
+       PINCTRL_PIN(14, "gpio14"),
+       PINCTRL_PIN(15, "gpio15"),
+       PINCTRL_PIN(16, "gpio16"),
+       PINCTRL_PIN(17, "gpio17"),
+       PINCTRL_PIN(18, "gpio18"),
+       PINCTRL_PIN(19, "gpio19"),
+       PINCTRL_PIN(20, "gpio20"),
+       PINCTRL_PIN(21, "gpio21"),
+       PINCTRL_PIN(22, "gpio22"),
+       PINCTRL_PIN(23, "gpio23"),
+       PINCTRL_PIN(24, "gpio24"),
+       PINCTRL_PIN(25, "gpio25"),
+       PINCTRL_PIN(26, "gpio26"),
+       PINCTRL_PIN(27, "gpio27"),
+       PINCTRL_PIN(28, "gpio28"),
+       PINCTRL_PIN(29, "gpio29"),
+       PINCTRL_PIN(30, "gpio30"),
+       PINCTRL_PIN(31, "gpio31"),
+       PINCTRL_PIN(32, "gpio32"),
+       PINCTRL_PIN(33, "gpio33"),
+       PINCTRL_PIN(34, "gpio34"),
+};
+
+static const char * const oxnas_fct0_group[] = {
+       "gpio0",  "gpio1",  "gpio2",  "gpio3",
+       "gpio4",  "gpio5",  "gpio6",  "gpio7",
+       "gpio8",  "gpio9",  "gpio10", "gpio11",
+       "gpio12", "gpio13", "gpio14", "gpio15",
+       "gpio16", "gpio17", "gpio18", "gpio19",
+       "gpio20", "gpio21", "gpio22", "gpio23",
+       "gpio24", "gpio25", "gpio26", "gpio27",
+       "gpio28", "gpio29", "gpio30", "gpio31",
+       "gpio32", "gpio33", "gpio34"
+};
+
+static const char * const oxnas_fct3_group[] = {
+       "gpio0",  "gpio1",  "gpio2",  "gpio3",
+       "gpio4",  "gpio5",  "gpio6",  "gpio7",
+       "gpio8",  "gpio9",
+       "gpio20",
+       "gpio22", "gpio23", "gpio24", "gpio25",
+       "gpio26", "gpio27", "gpio28", "gpio29",
+       "gpio30", "gpio31", "gpio32", "gpio33",
+       "gpio34"
+};
+
+#define FUNCTION(_name, _gr)                                   \
+       {                                                       \
+               .name = #_name,                                 \
+               .groups = oxnas_##_gr##_group,                  \
+               .ngroups = ARRAY_SIZE(oxnas_##_gr##_group),     \
+       }
+
+static const struct oxnas_function oxnas_functions[] = {
+       FUNCTION(gpio, fct0),
+       FUNCTION(fct3, fct3),
+};
+
+#define OXNAS_PINCTRL_GROUP(_pin, _name, ...)                          \
+       {                                                               \
+               .name = #_name,                                         \
+               .pin = _pin,                                            \
+               .bank = _pin / PINS_PER_BANK,                           \
+               .functions = (struct oxnas_desc_function[]){            \
+                       __VA_ARGS__, { } },                             \
+       }
+
+#define OXNAS_PINCTRL_FUNCTION(_name, _fct)            \
+       {                                               \
+               .name = #_name,                         \
+               .fct = _fct,                            \
+       }
+
+static const struct oxnas_pin_group oxnas_groups[] = {
+       OXNAS_PINCTRL_GROUP(0, gpio0,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(1, gpio1,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(2, gpio2,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(3, gpio3,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(4, gpio4,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(5, gpio5,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(6, gpio6,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(7, gpio7,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(8, gpio8,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(9, gpio9,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(10, gpio10,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(11, gpio11,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(12, gpio12,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(13, gpio13,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(14, gpio14,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(15, gpio15,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(16, gpio16,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(17, gpio17,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(18, gpio18,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(19, gpio19,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(20, gpio20,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(21, gpio21,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0)),
+       OXNAS_PINCTRL_GROUP(22, gpio22,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(23, gpio23,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(24, gpio24,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(25, gpio25,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(26, gpio26,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(27, gpio27,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(28, gpio28,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(29, gpio29,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(30, gpio30,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(31, gpio31,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(32, gpio32,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(33, gpio33,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+       OXNAS_PINCTRL_GROUP(34, gpio34,
+                       OXNAS_PINCTRL_FUNCTION(gpio, 0),
+                       OXNAS_PINCTRL_FUNCTION(fct3, 3)),
+};
+
+static inline struct oxnas_gpio_bank *pctl_to_bank(struct oxnas_pinctrl *pctl,
+                                                  unsigned int pin)
+{
+       return &pctl->gpio_banks[pin / PINS_PER_BANK];
+}
+
+static int oxnas_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+       struct oxnas_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+       return pctl->ngroups;
+}
+
+static const char *oxnas_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+                                               unsigned int group)
+{
+       struct oxnas_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+       return pctl->groups[group].name;
+}
+
+static int oxnas_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+                                       unsigned int group,
+                                       const unsigned int **pins,
+                                       unsigned int *num_pins)
+{
+       struct oxnas_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+       *pins = &pctl->groups[group].pin;
+       *num_pins = 1;
+
+       return 0;
+}
+
+static const struct pinctrl_ops oxnas_pinctrl_ops = {
+       .get_groups_count = oxnas_pinctrl_get_groups_count,
+       .get_group_name = oxnas_pinctrl_get_group_name,
+       .get_group_pins = oxnas_pinctrl_get_group_pins,
+       .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
+       .dt_free_map = pinctrl_utils_free_map,
+};
+
+static int oxnas_pinmux_get_functions_count(struct pinctrl_dev *pctldev)
+{
+       struct oxnas_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+       return pctl->nfunctions;
+}
+
+static const char *
+oxnas_pinmux_get_function_name(struct pinctrl_dev *pctldev, unsigned int func)
+{
+       struct oxnas_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+       return pctl->functions[func].name;
+}
+
+static int oxnas_pinmux_get_function_groups(struct pinctrl_dev *pctldev,
+                                           unsigned int func,
+                                           const char * const **groups,
+                                           unsigned int * const num_groups)
+{
+       struct oxnas_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+       *groups = pctl->functions[func].groups;
+       *num_groups = pctl->functions[func].ngroups;
+
+       return 0;
+}
+
+static int oxnas_pinmux_enable(struct pinctrl_dev *pctldev,
+                              unsigned int func, unsigned int group)
+{
+       struct oxnas_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       const struct oxnas_pin_group *pg = &pctl->groups[group];
+       const struct oxnas_function *pf = &pctl->functions[func];
+       const char *fname = pf->name;
+       struct oxnas_desc_function *functions = pg->functions;
+       u32 mask = BIT(pg->pin);
+
+       while (functions->name) {
+               if (!strcmp(functions->name, fname)) {
+                       dev_dbg(pctl->dev,
+                               "setting function %s bank %d pin %d fct %d mask %x\n",
+                               fname, pg->bank, pg->pin,
+                               functions->fct, mask);
+
+                       regmap_write_bits(pctl->regmap,
+                                         (pg->bank ?
+                                               PINMUX_PRIMARY_SEL1 :
+                                               PINMUX_PRIMARY_SEL0),
+                                         mask,
+                                         (functions->fct == 1 ?
+                                               mask : 0));
+                       regmap_write_bits(pctl->regmap,
+                                         (pg->bank ?
+                                               PINMUX_SECONDARY_SEL1 :
+                                               PINMUX_SECONDARY_SEL0),
+                                         mask,
+                                         (functions->fct == 2 ?
+                                               mask : 0));
+                       regmap_write_bits(pctl->regmap,
+                                         (pg->bank ?
+                                               PINMUX_TERTIARY_SEL1 :
+                                               PINMUX_TERTIARY_SEL0),
+                                         mask,
+                                         (functions->fct == 3 ?
+                                               mask : 0));
+
+                       return 0;
+               }
+
+               functions++;
+       }
+
+       dev_err(pctl->dev, "cannot mux pin %u to function %u\n", group, func);
+
+       return -EINVAL;
+}
+
+static int oxnas_gpio_request_enable(struct pinctrl_dev *pctldev,
+                                    struct pinctrl_gpio_range *range,
+                                    unsigned int offset)
+{
+       struct oxnas_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       struct oxnas_gpio_bank *bank = gpiochip_get_data(range->gc);
+       u32 mask = BIT(offset - bank->gpio_chip.base);
+
+       dev_dbg(pctl->dev, "requesting gpio %d in bank %d (id %d) with mask 0x%x\n",
+               offset, bank->gpio_chip.base, bank->id, mask);
+
+       regmap_write_bits(pctl->regmap,
+                         (bank->id ?
+                               PINMUX_PRIMARY_SEL1 :
+                               PINMUX_PRIMARY_SEL0),
+                         mask, 0);
+       regmap_write_bits(pctl->regmap,
+                         (bank->id ?
+                               PINMUX_SECONDARY_SEL1 :
+                               PINMUX_SECONDARY_SEL0),
+                         mask, 0);
+       regmap_write_bits(pctl->regmap,
+                         (bank->id ?
+                               PINMUX_TERTIARY_SEL1 :
+                               PINMUX_TERTIARY_SEL0),
+                         mask, 0);
+
+       return 0;
+}
+
+static int oxnas_gpio_get_direction(struct gpio_chip *chip,
+                                     unsigned int offset)
+{
+       struct oxnas_gpio_bank *bank = gpiochip_get_data(chip);
+       u32 mask = BIT(offset);
+
+       return !(readl_relaxed(bank->reg_base + OUTPUT_EN) & mask);
+}
+
+static int oxnas_gpio_direction_input(struct gpio_chip *chip,
+                                     unsigned int offset)
+{
+       struct oxnas_gpio_bank *bank = gpiochip_get_data(chip);
+       u32 mask = BIT(offset);
+
+       writel_relaxed(mask, bank->reg_base + OUTPUT_EN_CLEAR);
+
+       return 0;
+}
+
+static int oxnas_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+       struct oxnas_gpio_bank *bank = gpiochip_get_data(chip);
+       u32 mask = BIT(offset);
+
+       return (readl_relaxed(bank->reg_base + INPUT_VALUE) & mask) != 0;
+}
+
+static void oxnas_gpio_set(struct gpio_chip *chip, unsigned int offset,
+                              int value)
+{
+       struct oxnas_gpio_bank *bank = gpiochip_get_data(chip);
+       u32 mask = BIT(offset);
+
+       if (value)
+               writel_relaxed(mask, bank->reg_base + OUTPUT_SET);
+       else
+               writel_relaxed(mask, bank->reg_base + OUTPUT_CLEAR);
+}
+
+static int oxnas_gpio_direction_output(struct gpio_chip *chip,
+                                      unsigned int offset, int value)
+{
+       struct oxnas_gpio_bank *bank = gpiochip_get_data(chip);
+       u32 mask = BIT(offset);
+
+       oxnas_gpio_set(chip, offset, value);
+       writel_relaxed(mask, bank->reg_base + OUTPUT_EN_SET);
+
+       return 0;
+}
+
+static int oxnas_gpio_set_direction(struct pinctrl_dev *pctldev,
+                                   struct pinctrl_gpio_range *range,
+                                   unsigned int offset, bool input)
+{
+       struct gpio_chip *chip = range->gc;
+
+       if (input)
+               oxnas_gpio_direction_input(chip, offset);
+       else
+               oxnas_gpio_direction_output(chip, offset, 0);
+
+       return 0;
+}
+
+static const struct pinmux_ops oxnas_pinmux_ops = {
+       .get_functions_count = oxnas_pinmux_get_functions_count,
+       .get_function_name = oxnas_pinmux_get_function_name,
+       .get_function_groups = oxnas_pinmux_get_function_groups,
+       .set_mux = oxnas_pinmux_enable,
+       .gpio_request_enable = oxnas_gpio_request_enable,
+       .gpio_set_direction = oxnas_gpio_set_direction,
+};
+
+static int oxnas_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
+                            unsigned long *config)
+{
+       struct oxnas_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       struct oxnas_gpio_bank *bank = pctl_to_bank(pctl, pin);
+       unsigned int param = pinconf_to_config_param(*config);
+       u32 mask = BIT(pin - bank->gpio_chip.base);
+       int ret;
+       u32 arg;
+
+       switch (param) {
+       case PIN_CONFIG_BIAS_PULL_UP:
+               ret = regmap_read(pctl->regmap,
+                                 (bank->id ?
+                                       PINMUX_PULLUP_CTRL1 :
+                                       PINMUX_PULLUP_CTRL0),
+                                 &arg);
+               if (ret)
+                       return ret;
+
+               arg = !!(arg & mask);
+               break;
+       default:
+               return -ENOTSUPP;
+       }
+
+       *config = pinconf_to_config_packed(param, arg);
+
+       return 0;
+}
+
+static int oxnas_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+                            unsigned long *configs, unsigned int num_configs)
+{
+       struct oxnas_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       struct oxnas_gpio_bank *bank = pctl_to_bank(pctl, pin);
+       unsigned int param;
+       u32 arg;
+       unsigned int i;
+       u32 offset = pin - bank->gpio_chip.base;
+       u32 mask = BIT(offset);
+
+       dev_dbg(pctl->dev, "setting pin %d bank %d mask 0x%x\n",
+               pin, bank->gpio_chip.base, mask);
+
+       for (i = 0; i < num_configs; i++) {
+               param = pinconf_to_config_param(configs[i]);
+               arg = pinconf_to_config_argument(configs[i]);
+
+               switch (param) {
+               case PIN_CONFIG_BIAS_PULL_UP:
+                       dev_dbg(pctl->dev, "   pullup\n");
+                       regmap_write_bits(pctl->regmap,
+                                         (bank->id ?
+                                               PINMUX_PULLUP_CTRL1 :
+                                               PINMUX_PULLUP_CTRL0),
+                                         mask, mask);
+                       break;
+               default:
+                       dev_err(pctl->dev, "Property %u not supported\n",
+                               param);
+                       return -ENOTSUPP;
+               }
+       }
+
+       return 0;
+}
+
+static const struct pinconf_ops oxnas_pinconf_ops = {
+       .pin_config_get = oxnas_pinconf_get,
+       .pin_config_set = oxnas_pinconf_set,
+       .is_generic = true,
+};
+
+static struct pinctrl_desc oxnas_pinctrl_desc = {
+       .name = "oxnas-pinctrl",
+       .pctlops = &oxnas_pinctrl_ops,
+       .pmxops = &oxnas_pinmux_ops,
+       .confops = &oxnas_pinconf_ops,
+       .owner = THIS_MODULE,
+};
+
+static void oxnas_gpio_irq_ack(struct irq_data *data)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+       struct oxnas_gpio_bank *bank = gpiochip_get_data(chip);
+       u32 mask = BIT(data->hwirq);
+
+       writel(mask, bank->reg_base + IRQ_PENDING);
+}
+
+static void oxnas_gpio_irq_mask(struct irq_data *data)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+       struct oxnas_gpio_bank *bank = gpiochip_get_data(chip);
+       unsigned int type = irqd_get_trigger_type(data);
+       u32 mask = BIT(data->hwirq);
+
+       if (type & IRQ_TYPE_EDGE_RISING)
+               writel(readl(bank->reg_base + RE_IRQ_ENABLE) & ~mask,
+                      bank->reg_base + RE_IRQ_ENABLE);
+
+       if (type & IRQ_TYPE_EDGE_FALLING)
+               writel(readl(bank->reg_base + FE_IRQ_ENABLE) & ~mask,
+                      bank->reg_base + FE_IRQ_ENABLE);
+}
+
+static void oxnas_gpio_irq_unmask(struct irq_data *data)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+       struct oxnas_gpio_bank *bank = gpiochip_get_data(chip);
+       unsigned int type = irqd_get_trigger_type(data);
+       u32 mask = BIT(data->hwirq);
+
+       if (type & IRQ_TYPE_EDGE_RISING)
+               writel(readl(bank->reg_base + RE_IRQ_ENABLE) | mask,
+                      bank->reg_base + RE_IRQ_ENABLE);
+
+       if (type & IRQ_TYPE_EDGE_FALLING)
+               writel(readl(bank->reg_base + FE_IRQ_ENABLE) | mask,
+                      bank->reg_base + FE_IRQ_ENABLE);
+}
+
+static unsigned int oxnas_gpio_irq_startup(struct irq_data *data)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+
+       oxnas_gpio_direction_input(chip, data->hwirq);
+       oxnas_gpio_irq_unmask(data);
+
+       return 0;
+}
+
+static int oxnas_gpio_irq_set_type(struct irq_data *data, unsigned int type)
+{
+       if ((type & (IRQ_TYPE_EDGE_RISING|IRQ_TYPE_EDGE_FALLING)) == 0)
+               return -EINVAL;
+
+       irq_set_handler_locked(data, handle_edge_irq);
+
+       return 0;
+}
+
+static void oxnas_gpio_irq_handler(struct irq_desc *desc)
+{
+       struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+       struct oxnas_gpio_bank *bank = gpiochip_get_data(gc);
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       unsigned long stat;
+       unsigned int pin;
+
+       chained_irq_enter(chip, desc);
+
+       stat = readl(bank->reg_base + IRQ_PENDING);
+
+       for_each_set_bit(pin, &stat, BITS_PER_LONG)
+               generic_handle_irq(irq_linear_revmap(gc->irqdomain, pin));
+
+       chained_irq_exit(chip, desc);
+}
+
+#define GPIO_BANK(_bank)                                               \
+       {                                                               \
+               .gpio_chip = {                                          \
+                       .label = "GPIO" #_bank,                         \
+                       .request = gpiochip_generic_request,            \
+                       .free = gpiochip_generic_free,                  \
+                       .get_direction = oxnas_gpio_get_direction,      \
+                       .direction_input = oxnas_gpio_direction_input,  \
+                       .direction_output = oxnas_gpio_direction_output, \
+                       .get = oxnas_gpio_get,                          \
+                       .set = oxnas_gpio_set,                          \
+                       .ngpio = PINS_PER_BANK,                         \
+                       .base = GPIO_BANK_START(_bank),                 \
+                       .owner = THIS_MODULE,                           \
+                       .can_sleep = 0,                                 \
+               },                                                      \
+               .irq_chip = {                                           \
+                       .name = "GPIO" #_bank,                          \
+                       .irq_startup = oxnas_gpio_irq_startup,  \
+                       .irq_ack = oxnas_gpio_irq_ack,          \
+                       .irq_mask = oxnas_gpio_irq_mask,                \
+                       .irq_unmask = oxnas_gpio_irq_unmask,            \
+                       .irq_set_type = oxnas_gpio_irq_set_type,        \
+               },                                                      \
+       }
+
+static struct oxnas_gpio_bank oxnas_gpio_banks[] = {
+       GPIO_BANK(0),
+       GPIO_BANK(1),
+};
+
+static int oxnas_pinctrl_probe(struct platform_device *pdev)
+{
+       struct oxnas_pinctrl *pctl;
+
+       pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
+       if (!pctl)
+               return -ENOMEM;
+       pctl->dev = &pdev->dev;
+       dev_set_drvdata(&pdev->dev, pctl);
+
+       pctl->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+                                                      "oxsemi,sys-ctrl");
+       if (IS_ERR(pctl->regmap)) {
+               dev_err(&pdev->dev, "failed to get sys ctrl regmap\n");
+               return -ENODEV;
+       }
+
+       pctl->pins = oxnas_pins;
+       pctl->npins = ARRAY_SIZE(oxnas_pins);
+       pctl->functions = oxnas_functions;
+       pctl->nfunctions = ARRAY_SIZE(oxnas_functions);
+       pctl->groups = oxnas_groups;
+       pctl->ngroups = ARRAY_SIZE(oxnas_groups);
+       pctl->gpio_banks = oxnas_gpio_banks;
+       pctl->nbanks = ARRAY_SIZE(oxnas_gpio_banks);
+
+       oxnas_pinctrl_desc.pins = pctl->pins;
+       oxnas_pinctrl_desc.npins = pctl->npins;
+
+       pctl->pctldev = pinctrl_register(&oxnas_pinctrl_desc,
+                                        &pdev->dev, pctl);
+       if (IS_ERR(pctl->pctldev)) {
+               dev_err(&pdev->dev, "Failed to register pinctrl device\n");
+               return PTR_ERR(pctl->pctldev);
+       }
+
+       return 0;
+}
+
+static int oxnas_gpio_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct of_phandle_args pinspec;
+       struct oxnas_gpio_bank *bank;
+       unsigned int id, ngpios;
+       int irq, ret;
+       struct resource *res;
+
+       if (of_parse_phandle_with_fixed_args(np, "gpio-ranges",
+                                            3, 0, &pinspec)) {
+               dev_err(&pdev->dev, "gpio-ranges property not found\n");
+               return -EINVAL;
+       }
+
+       id = pinspec.args[1] / PINS_PER_BANK;
+       ngpios = pinspec.args[2];
+
+       if (id >= ARRAY_SIZE(oxnas_gpio_banks)) {
+               dev_err(&pdev->dev, "invalid gpio-ranges base arg\n");
+               return -EINVAL;
+       }
+
+       if (ngpios > PINS_PER_BANK) {
+               dev_err(&pdev->dev, "invalid gpio-ranges count arg\n");
+               return -EINVAL;
+       }
+
+       bank = &oxnas_gpio_banks[id];
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       bank->reg_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(bank->reg_base))
+               return PTR_ERR(bank->reg_base);
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "irq get failed\n");
+               return irq;
+       }
+
+       bank->id = id;
+       bank->gpio_chip.parent = &pdev->dev;
+       bank->gpio_chip.of_node = np;
+       bank->gpio_chip.ngpio = ngpios;
+       ret = gpiochip_add_data(&bank->gpio_chip, bank);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to add GPIO chip %u: %d\n",
+                       id, ret);
+               return ret;
+       }
+
+       ret = gpiochip_irqchip_add(&bank->gpio_chip, &bank->irq_chip,
+                               0, handle_level_irq, IRQ_TYPE_NONE);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to add IRQ chip %u: %d\n",
+                       id, ret);
+               gpiochip_remove(&bank->gpio_chip);
+               return ret;
+       }
+
+       gpiochip_set_chained_irqchip(&bank->gpio_chip, &bank->irq_chip,
+                                    irq, oxnas_gpio_irq_handler);
+
+       return 0;
+}
+
+static const struct of_device_id oxnas_pinctrl_of_match[] = {
+       { .compatible = "oxsemi,ox810se-pinctrl", },
+       { },
+};
+
+static struct platform_driver oxnas_pinctrl_driver = {
+       .driver = {
+               .name = "oxnas-pinctrl",
+               .of_match_table = oxnas_pinctrl_of_match,
+               .suppress_bind_attrs = true,
+       },
+       .probe = oxnas_pinctrl_probe,
+};
+
+static const struct of_device_id oxnas_gpio_of_match[] = {
+       { .compatible = "oxsemi,ox810se-gpio", },
+       { },
+};
+
+static struct platform_driver oxnas_gpio_driver = {
+       .driver = {
+               .name = "oxnas-gpio",
+               .of_match_table = oxnas_gpio_of_match,
+               .suppress_bind_attrs = true,
+       },
+       .probe = oxnas_gpio_probe,
+};
+
+static int __init oxnas_gpio_register(void)
+{
+       return platform_driver_register(&oxnas_gpio_driver);
+}
+arch_initcall(oxnas_gpio_register);
+
+static int __init oxnas_pinctrl_register(void)
+{
+       return platform_driver_register(&oxnas_pinctrl_driver);
+}
+arch_initcall(oxnas_pinctrl_register);
index a91026e..44902c6 100644 (file)
@@ -360,7 +360,7 @@ static struct regmap_config rockchip_regmap_config = {
        .reg_stride = 4,
 };
 
-static const inline struct rockchip_pin_group *pinctrl_name_to_group(
+static inline const struct rockchip_pin_group *pinctrl_name_to_group(
                                        const struct rockchip_pinctrl *info,
                                        const char *name)
 {
@@ -2007,7 +2007,7 @@ static void rockchip_irq_gc_mask_clr_bit(struct irq_data *d)
        irq_gc_mask_clr_bit(d);
 }
 
-void rockchip_irq_gc_mask_set_bit(struct irq_data *d)
+static void rockchip_irq_gc_mask_set_bit(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
        struct rockchip_pin_bank *bank = gc->private;
index d0ba968..0de1c67 100644 (file)
@@ -844,7 +844,7 @@ static int st_pctl_get_group_pins(struct pinctrl_dev *pctldev,
        return 0;
 }
 
-static const inline struct st_pctl_group *st_pctl_find_group_by_name(
+static inline const struct st_pctl_group *st_pctl_find_group_by_name(
        const struct st_pinctrl *info, const char *name)
 {
        int i;
index d1af908..9cc80a5 100644 (file)
@@ -670,7 +670,7 @@ struct u300_pmx {
  * u300_pmx_registers - the array of registers read/written for each pinmux
  * shunt setting
  */
-const u32 u300_pmx_registers[] = {
+static const u32 u300_pmx_registers[] = {
        U300_SYSCON_PMC1LR,
        U300_SYSCON_PMC1HR,
        U300_SYSCON_PMC2R,
index b937554..dd85ad1 100644 (file)
@@ -1616,50 +1616,74 @@ struct pinctrl_xway_soc {
 
 /* xway xr9 series (DEPRECATED: Use XWAY xRX100/xRX200 Family) */
 static struct pinctrl_xway_soc xr9_pinctrl = {
-       XR9_MAX_PIN, xway_mfp,
-       xway_grps, ARRAY_SIZE(xway_grps),
-       xrx_funcs, ARRAY_SIZE(xrx_funcs),
-       xway_exin_pin_map, 6
+       .pin_count = XR9_MAX_PIN,
+       .mfp = xway_mfp,
+       .grps = xway_grps,
+       .num_grps = ARRAY_SIZE(xway_grps),
+       .funcs = xrx_funcs,
+       .num_funcs = ARRAY_SIZE(xrx_funcs),
+       .exin = xway_exin_pin_map,
+       .num_exin = 6
 };
 
 /* XWAY AMAZON Family */
 static struct pinctrl_xway_soc ase_pinctrl = {
-       ASE_MAX_PIN, ase_mfp,
-       ase_grps, ARRAY_SIZE(ase_grps),
-       ase_funcs, ARRAY_SIZE(ase_funcs),
-       ase_exin_pin_map, 3
+       .pin_count = ASE_MAX_PIN,
+       .mfp = ase_mfp,
+       .grps = ase_grps,
+       .num_grps = ARRAY_SIZE(ase_grps),
+       .funcs = ase_funcs,
+       .num_funcs = ARRAY_SIZE(ase_funcs),
+       .exin = ase_exin_pin_map,
+       .num_exin = 3
 };
 
 /* XWAY DANUBE Family */
 static struct pinctrl_xway_soc danube_pinctrl = {
-       DANUBE_MAX_PIN, danube_mfp,
-       danube_grps, ARRAY_SIZE(danube_grps),
-       danube_funcs, ARRAY_SIZE(danube_funcs),
-       danube_exin_pin_map, 3
+       .pin_count = DANUBE_MAX_PIN,
+       .mfp = danube_mfp,
+       .grps = danube_grps,
+       .num_grps = ARRAY_SIZE(danube_grps),
+       .funcs = danube_funcs,
+       .num_funcs = ARRAY_SIZE(danube_funcs),
+       .exin = danube_exin_pin_map,
+       .num_exin = 3
 };
 
 /* XWAY xRX100 Family */
 static struct pinctrl_xway_soc xrx100_pinctrl = {
-       XRX100_MAX_PIN, xrx100_mfp,
-       xrx100_grps, ARRAY_SIZE(xrx100_grps),
-       xrx100_funcs, ARRAY_SIZE(xrx100_funcs),
-       xrx100_exin_pin_map, 6
+       .pin_count = XRX100_MAX_PIN,
+       .mfp = xrx100_mfp,
+       .grps = xrx100_grps,
+       .num_grps = ARRAY_SIZE(xrx100_grps),
+       .funcs = xrx100_funcs,
+       .num_funcs = ARRAY_SIZE(xrx100_funcs),
+       .exin = xrx100_exin_pin_map,
+       .num_exin = 6
 };
 
 /* XWAY xRX200 Family */
 static struct pinctrl_xway_soc xrx200_pinctrl = {
-       XRX200_MAX_PIN, xrx200_mfp,
-       xrx200_grps, ARRAY_SIZE(xrx200_grps),
-       xrx200_funcs, ARRAY_SIZE(xrx200_funcs),
-       xrx200_exin_pin_map, 6
+       .pin_count = XRX200_MAX_PIN,
+       .mfp = xrx200_mfp,
+       .grps = xrx200_grps,
+       .num_grps = ARRAY_SIZE(xrx200_grps),
+       .funcs = xrx200_funcs,
+       .num_funcs = ARRAY_SIZE(xrx200_funcs),
+       .exin = xrx200_exin_pin_map,
+       .num_exin = 6
 };
 
 /* XWAY xRX300 Family */
 static struct pinctrl_xway_soc xrx300_pinctrl = {
-       XRX300_MAX_PIN, xrx300_mfp,
-       xrx300_grps, ARRAY_SIZE(xrx300_grps),
-       xrx300_funcs, ARRAY_SIZE(xrx300_funcs),
-       xrx300_exin_pin_map, 5
+       .pin_count = XRX300_MAX_PIN,
+       .mfp = xrx300_mfp,
+       .grps = xrx300_grps,
+       .num_grps = ARRAY_SIZE(xrx300_grps),
+       .funcs = xrx300_funcs,
+       .num_funcs = ARRAY_SIZE(xrx300_funcs),
+       .exin = xrx300_exin_pin_map,
+       .num_exin = 5
 };
 
 static struct pinctrl_gpio_range xway_gpio_range = {
index 8fdc60c..7afdbed 100644 (file)
@@ -20,7 +20,7 @@
  */
 #include <linux/io.h>
 #include <linux/mfd/syscon.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -1210,7 +1210,6 @@ static const struct of_device_id zynq_pinctrl_of_match[] = {
        { .compatible = "xlnx,pinctrl-zynq" },
        { }
 };
-MODULE_DEVICE_TABLE(of, zynq_pinctrl_of_match);
 
 static struct platform_driver zynq_pinctrl_driver = {
        .driver = {
@@ -1225,13 +1224,3 @@ static int __init zynq_pinctrl_init(void)
        return platform_driver_register(&zynq_pinctrl_driver);
 }
 arch_initcall(zynq_pinctrl_init);
-
-static void __exit zynq_pinctrl_exit(void)
-{
-       platform_driver_unregister(&zynq_pinctrl_driver);
-}
-module_exit(zynq_pinctrl_exit);
-
-MODULE_AUTHOR("Sören Brinkmann <soren.brinkmann@xilinx.com>");
-MODULE_DESCRIPTION("Xilinx Zynq pinctrl driver");
-MODULE_LICENSE("GPL");
index c223a9e..ece7028 100644 (file)
@@ -256,7 +256,7 @@ int pinmux_request_gpio(struct pinctrl_dev *pctldev,
        /* Conjure some name stating what chip and pin this is taken by */
        owner = kasprintf(GFP_KERNEL, "%s:%d", range->name, gpio);
        if (!owner)
-               return -EINVAL;
+               return -ENOMEM;
 
        ret = pin_request(pctldev, pin, owner, range);
        if (ret < 0)
@@ -606,23 +606,17 @@ static int pinmux_pins_show(struct seq_file *s, void *what)
                if (pmxops->strict) {
                        if (desc->mux_owner)
                                seq_printf(s, "pin %d (%s): device %s%s",
-                                          pin,
-                                          desc->name ? desc->name : "unnamed",
-                                          desc->mux_owner,
+                                          pin, desc->name, desc->mux_owner,
                                           is_hog ? " (HOG)" : "");
                        else if (desc->gpio_owner)
                                seq_printf(s, "pin %d (%s): GPIO %s",
-                                          pin,
-                                          desc->name ? desc->name : "unnamed",
-                                          desc->gpio_owner);
+                                          pin, desc->name, desc->gpio_owner);
                        else
                                seq_printf(s, "pin %d (%s): UNCLAIMED",
-                                          pin,
-                                          desc->name ? desc->name : "unnamed");
+                                          pin, desc->name);
                } else {
                        /* For non-strict controllers */
-                       seq_printf(s, "pin %d (%s): %s %s%s", pin,
-                                  desc->name ? desc->name : "unnamed",
+                       seq_printf(s, "pin %d (%s): %s %s%s", pin, desc->name,
                                   desc->mux_owner ? desc->mux_owner
                                   : "(MUX UNCLAIMED)",
                                   desc->gpio_owner ? desc->gpio_owner
index 67bc70d..93ef268 100644 (file)
@@ -55,6 +55,14 @@ config PINCTRL_MSM8960
          This is the pinctrl, pinmux, pinconf and gpiolib driver for the
          Qualcomm TLMM block found in the Qualcomm 8960 platform.
 
+config PINCTRL_MDM9615
+       tristate "Qualcomm 9615 pin controller driver"
+       depends on GPIOLIB && OF
+       select PINCTRL_MSM
+       help
+         This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+         Qualcomm TLMM block found in the Qualcomm 9615 platform.
+
 config PINCTRL_MSM8X74
        tristate "Qualcomm 8x74 pin controller driver"
        depends on GPIOLIB && OF
index c964a2c..8319e11 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_PINCTRL_MSM8X74) += pinctrl-msm8x74.o
 obj-$(CONFIG_PINCTRL_MSM8916)  += pinctrl-msm8916.o
 obj-$(CONFIG_PINCTRL_MSM8996)   += pinctrl-msm8996.o
 obj-$(CONFIG_PINCTRL_QDF2XXX)  += pinctrl-qdf2xxx.o
+obj-$(CONFIG_PINCTRL_MDM9615)  += pinctrl-mdm9615.o
 obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o
 obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o
 obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o
diff --git a/drivers/pinctrl/qcom/pinctrl-mdm9615.c b/drivers/pinctrl/qcom/pinctrl-mdm9615.c
new file mode 100644 (file)
index 0000000..2b8f452
--- /dev/null
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 2014, Sony Mobile Communications AB.
+ * Copyright (c) 2016 BayLibre, SAS.
+ * Author : Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "pinctrl-msm.h"
+
+static const struct pinctrl_pin_desc mdm9615_pins[] = {
+       PINCTRL_PIN(0, "GPIO_0"),
+       PINCTRL_PIN(1, "GPIO_1"),
+       PINCTRL_PIN(2, "GPIO_2"),
+       PINCTRL_PIN(3, "GPIO_3"),
+       PINCTRL_PIN(4, "GPIO_4"),
+       PINCTRL_PIN(5, "GPIO_5"),
+       PINCTRL_PIN(6, "GPIO_6"),
+       PINCTRL_PIN(7, "GPIO_7"),
+       PINCTRL_PIN(8, "GPIO_8"),
+       PINCTRL_PIN(9, "GPIO_9"),
+       PINCTRL_PIN(10, "GPIO_10"),
+       PINCTRL_PIN(11, "GPIO_11"),
+       PINCTRL_PIN(12, "GPIO_12"),
+       PINCTRL_PIN(13, "GPIO_13"),
+       PINCTRL_PIN(14, "GPIO_14"),
+       PINCTRL_PIN(15, "GPIO_15"),
+       PINCTRL_PIN(16, "GPIO_16"),
+       PINCTRL_PIN(17, "GPIO_17"),
+       PINCTRL_PIN(18, "GPIO_18"),
+       PINCTRL_PIN(19, "GPIO_19"),
+       PINCTRL_PIN(20, "GPIO_20"),
+       PINCTRL_PIN(21, "GPIO_21"),
+       PINCTRL_PIN(22, "GPIO_22"),
+       PINCTRL_PIN(23, "GPIO_23"),
+       PINCTRL_PIN(24, "GPIO_24"),
+       PINCTRL_PIN(25, "GPIO_25"),
+       PINCTRL_PIN(26, "GPIO_26"),
+       PINCTRL_PIN(27, "GPIO_27"),
+       PINCTRL_PIN(28, "GPIO_28"),
+       PINCTRL_PIN(29, "GPIO_29"),
+       PINCTRL_PIN(30, "GPIO_30"),
+       PINCTRL_PIN(31, "GPIO_31"),
+       PINCTRL_PIN(32, "GPIO_32"),
+       PINCTRL_PIN(33, "GPIO_33"),
+       PINCTRL_PIN(34, "GPIO_34"),
+       PINCTRL_PIN(35, "GPIO_35"),
+       PINCTRL_PIN(36, "GPIO_36"),
+       PINCTRL_PIN(37, "GPIO_37"),
+       PINCTRL_PIN(38, "GPIO_38"),
+       PINCTRL_PIN(39, "GPIO_39"),
+       PINCTRL_PIN(40, "GPIO_40"),
+       PINCTRL_PIN(41, "GPIO_41"),
+       PINCTRL_PIN(42, "GPIO_42"),
+       PINCTRL_PIN(43, "GPIO_43"),
+       PINCTRL_PIN(44, "GPIO_44"),
+       PINCTRL_PIN(45, "GPIO_45"),
+       PINCTRL_PIN(46, "GPIO_46"),
+       PINCTRL_PIN(47, "GPIO_47"),
+       PINCTRL_PIN(48, "GPIO_48"),
+       PINCTRL_PIN(49, "GPIO_49"),
+       PINCTRL_PIN(50, "GPIO_50"),
+       PINCTRL_PIN(51, "GPIO_51"),
+       PINCTRL_PIN(52, "GPIO_52"),
+       PINCTRL_PIN(53, "GPIO_53"),
+       PINCTRL_PIN(54, "GPIO_54"),
+       PINCTRL_PIN(55, "GPIO_55"),
+       PINCTRL_PIN(56, "GPIO_56"),
+       PINCTRL_PIN(57, "GPIO_57"),
+       PINCTRL_PIN(58, "GPIO_58"),
+       PINCTRL_PIN(59, "GPIO_59"),
+       PINCTRL_PIN(60, "GPIO_60"),
+       PINCTRL_PIN(61, "GPIO_61"),
+       PINCTRL_PIN(62, "GPIO_62"),
+       PINCTRL_PIN(63, "GPIO_63"),
+       PINCTRL_PIN(64, "GPIO_64"),
+       PINCTRL_PIN(65, "GPIO_65"),
+       PINCTRL_PIN(66, "GPIO_66"),
+       PINCTRL_PIN(67, "GPIO_67"),
+       PINCTRL_PIN(68, "GPIO_68"),
+       PINCTRL_PIN(69, "GPIO_69"),
+       PINCTRL_PIN(70, "GPIO_70"),
+       PINCTRL_PIN(71, "GPIO_71"),
+       PINCTRL_PIN(72, "GPIO_72"),
+       PINCTRL_PIN(73, "GPIO_73"),
+       PINCTRL_PIN(74, "GPIO_74"),
+       PINCTRL_PIN(75, "GPIO_75"),
+       PINCTRL_PIN(76, "GPIO_76"),
+       PINCTRL_PIN(77, "GPIO_77"),
+       PINCTRL_PIN(78, "GPIO_78"),
+       PINCTRL_PIN(79, "GPIO_79"),
+       PINCTRL_PIN(80, "GPIO_80"),
+       PINCTRL_PIN(81, "GPIO_81"),
+       PINCTRL_PIN(82, "GPIO_82"),
+       PINCTRL_PIN(83, "GPIO_83"),
+       PINCTRL_PIN(84, "GPIO_84"),
+       PINCTRL_PIN(85, "GPIO_85"),
+       PINCTRL_PIN(86, "GPIO_86"),
+       PINCTRL_PIN(87, "GPIO_87"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+       static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+
+#define FUNCTION(fname)                                        \
+       [MSM_MUX_##fname] = {                           \
+               .name = #fname,                         \
+               .groups = fname##_groups,               \
+               .ngroups = ARRAY_SIZE(fname##_groups),  \
+       }
+
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11) \
+       {                                               \
+               .name = "gpio" #id,                     \
+               .pins = gpio##id##_pins,                \
+               .npins = ARRAY_SIZE(gpio##id##_pins),   \
+               .funcs = (int[]){                       \
+                       MSM_MUX_gpio,                   \
+                       MSM_MUX_##f1,                   \
+                       MSM_MUX_##f2,                   \
+                       MSM_MUX_##f3,                   \
+                       MSM_MUX_##f4,                   \
+                       MSM_MUX_##f5,                   \
+                       MSM_MUX_##f6,                   \
+                       MSM_MUX_##f7,                   \
+                       MSM_MUX_##f8,                   \
+                       MSM_MUX_##f9,                   \
+                       MSM_MUX_##f10,                  \
+                       MSM_MUX_##f11                   \
+               },                                      \
+               .nfuncs = 12,                           \
+               .ctl_reg = 0x1000 + 0x10 * id,          \
+               .io_reg = 0x1004 + 0x10 * id,           \
+               .intr_cfg_reg = 0x1008 + 0x10 * id,     \
+               .intr_status_reg = 0x100c + 0x10 * id,  \
+               .intr_target_reg = 0x400 + 0x4 * id,    \
+               .mux_bit = 2,                           \
+               .pull_bit = 0,                          \
+               .drv_bit = 6,                           \
+               .oe_bit = 9,                            \
+               .in_bit = 0,                            \
+               .out_bit = 1,                           \
+               .intr_enable_bit = 0,                   \
+               .intr_status_bit = 0,                   \
+               .intr_ack_high = 1,                     \
+               .intr_target_bit = 0,                   \
+               .intr_target_kpss_val = 4,              \
+               .intr_raw_status_bit = 3,               \
+               .intr_polarity_bit = 1,                 \
+               .intr_detection_bit = 2,                \
+               .intr_detection_width = 1,              \
+       }
+
+enum mdm9615_functions {
+       MSM_MUX_gpio,
+       MSM_MUX_gsbi2_i2c,
+       MSM_MUX_gsbi3,
+       MSM_MUX_gsbi4,
+       MSM_MUX_gsbi5_i2c,
+       MSM_MUX_gsbi5_uart,
+       MSM_MUX_sdc2,
+       MSM_MUX_ebi2_lcdc,
+       MSM_MUX_ps_hold,
+       MSM_MUX_prim_audio,
+       MSM_MUX_sec_audio,
+       MSM_MUX_cdc_mclk,
+       MSM_MUX_NA,
+};
+
+static const char * const gpio_groups[] = {
+       "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+       "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+       "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+       "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+       "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+       "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+       "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+       "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+       "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+       "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+       "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+       "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+       "gpio85", "gpio86", "gpio87"
+};
+
+static const char * const gsbi2_i2c_groups[] = {
+       "gpio4", "gpio5"
+};
+
+static const char * const gsbi3_groups[] = {
+       "gpio8", "gpio9", "gpio10", "gpio11"
+};
+
+static const char * const gsbi4_groups[] = {
+       "gpio12", "gpio13", "gpio14", "gpio15"
+};
+
+static const char * const gsbi5_i2c_groups[] = {
+       "gpio16", "gpio17"
+};
+
+static const char * const gsbi5_uart_groups[] = {
+       "gpio18", "gpio19"
+};
+
+static const char * const sdc2_groups[] = {
+       "gpio25", "gpio26", "gpio27", "gpio28", "gpio29", "gpio30",
+};
+
+static const char * const ebi2_lcdc_groups[] = {
+       "gpio21", "gpio22", "gpio24",
+};
+
+static const char * const ps_hold_groups[] = {
+       "gpio83",
+};
+
+static const char * const prim_audio_groups[] = {
+       "gpio20", "gpio21", "gpio22", "gpio23",
+};
+
+static const char * const sec_audio_groups[] = {
+       "gpio25", "gpio26", "gpio27", "gpio28",
+};
+
+static const char * const cdc_mclk_groups[] = {
+       "gpio24",
+};
+
+static const struct msm_function mdm9615_functions[] = {
+       FUNCTION(gpio),
+       FUNCTION(gsbi2_i2c),
+       FUNCTION(gsbi3),
+       FUNCTION(gsbi4),
+       FUNCTION(gsbi5_i2c),
+       FUNCTION(gsbi5_uart),
+       FUNCTION(sdc2),
+       FUNCTION(ebi2_lcdc),
+       FUNCTION(ps_hold),
+       FUNCTION(prim_audio),
+       FUNCTION(sec_audio),
+       FUNCTION(cdc_mclk),
+};
+
+static const struct msm_pingroup mdm9615_groups[] = {
+       PINGROUP(0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(2, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(4, gsbi2_i2c, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(5, gsbi2_i2c, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(6, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(7, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(8, gsbi3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(9, gsbi3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(10, gsbi3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(11, gsbi3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(12, gsbi4, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(13, gsbi4, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(14, gsbi4, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(15, gsbi4, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(16, gsbi5_i2c, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(17, gsbi5_i2c, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(18, gsbi5_uart, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(19, gsbi5_uart, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(20, prim_audio, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(21, prim_audio, ebi2_lcdc, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(22, prim_audio, ebi2_lcdc, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(23, prim_audio, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(24, cdc_mclk, NA, ebi2_lcdc, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(25, sdc2, sec_audio, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(26, sdc2, sec_audio, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(27, sdc2, sec_audio, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(28, sdc2, sec_audio, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(29, sdc2, sec_audio, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(30, sdc2, sec_audio, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(31, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(32, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(33, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(34, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(35, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(36, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(37, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(38, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(39, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(40, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(41, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(42, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(43, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(44, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(45, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(46, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(47, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(48, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(49, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(50, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(51, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(52, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(53, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(54, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(55, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(56, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(57, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(58, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(59, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(60, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(61, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(62, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(63, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(64, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(65, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(66, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(67, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(68, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(69, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(70, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(71, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(72, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(73, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(74, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(75, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(76, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(77, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(78, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(79, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(80, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(81, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(82, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(83, ps_hold, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(84, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(85, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(86, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(87, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+};
+
+#define NUM_GPIO_PINGROUPS 88
+
+static const struct msm_pinctrl_soc_data mdm9615_pinctrl = {
+       .pins = mdm9615_pins,
+       .npins = ARRAY_SIZE(mdm9615_pins),
+       .functions = mdm9615_functions,
+       .nfunctions = ARRAY_SIZE(mdm9615_functions),
+       .groups = mdm9615_groups,
+       .ngroups = ARRAY_SIZE(mdm9615_groups),
+       .ngpios = NUM_GPIO_PINGROUPS,
+};
+
+static int mdm9615_pinctrl_probe(struct platform_device *pdev)
+{
+       return msm_pinctrl_probe(pdev, &mdm9615_pinctrl);
+}
+
+static const struct of_device_id mdm9615_pinctrl_of_match[] = {
+       { .compatible = "qcom,mdm9615-pinctrl", },
+       { },
+};
+
+static struct platform_driver mdm9615_pinctrl_driver = {
+       .driver = {
+               .name = "mdm9615-pinctrl",
+               .of_match_table = mdm9615_pinctrl_of_match,
+       },
+       .probe = mdm9615_pinctrl_probe,
+       .remove = msm_pinctrl_remove,
+};
+
+static int __init mdm9615_pinctrl_init(void)
+{
+       return platform_driver_register(&mdm9615_pinctrl_driver);
+}
+arch_initcall(mdm9615_pinctrl_init);
+
+static void __exit mdm9615_pinctrl_exit(void)
+{
+       platform_driver_unregister(&mdm9615_pinctrl_driver);
+}
+module_exit(mdm9615_pinctrl_exit);
+
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
+MODULE_DESCRIPTION("Qualcomm MDM9615 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, mdm9615_pinctrl_of_match);
index 1a44e1d..51c42d7 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/spinlock.h>
 #include <linux/reboot.h>
 #include <linux/pm.h>
+#include <linux/log2.h>
 
 #include "../core.h"
 #include "../pinconf.h"
@@ -138,10 +139,11 @@ static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev,
        struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
        const struct msm_pingroup *g;
        unsigned long flags;
-       u32 val;
+       u32 val, mask;
        int i;
 
        g = &pctrl->soc->groups[group];
+       mask = GENMASK(g->mux_bit + order_base_2(g->nfuncs) - 1, g->mux_bit);
 
        for (i = 0; i < g->nfuncs; i++) {
                if (g->funcs[i] == function)
@@ -154,7 +156,7 @@ static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev,
        spin_lock_irqsave(&pctrl->lock, flags);
 
        val = readl(pctrl->regs + g->ctl_reg);
-       val &= ~(0x7 << g->mux_bit);
+       val &= mask;
        val |= i << g->mux_bit;
        writel(val, pctrl->regs + g->ctl_reg);
 
index 3e8f7ac..5591d09 100644 (file)
@@ -506,6 +506,8 @@ enum msm8660_functions {
        MSM_MUX_usb_fs2_oe_n,
        MSM_MUX_vfe,
        MSM_MUX_vsens_alarm,
+       MSM_MUX_ebi2cs,
+       MSM_MUX_ebi2,
        MSM_MUX__,
 };
 
@@ -696,6 +698,36 @@ static const char * const vfe_groups[] = {
 static const char * const vsens_alarm_groups[] = {
        "gpio127"
 };
+static const char * const ebi2cs_groups[] = {
+       "gpio39", /* CS1A */
+       "gpio40", /* CS2A */
+       "gpio123", /* CS1B */
+       "gpio124", /* CS2B */
+       "gpio131", /* CS5 */
+       "gpio132", /* CS4 */
+       "gpio133", /* CS3 */
+       "gpio134", /* CS0 */
+};
+static const char * const ebi2_groups[] = {
+       /* ADDR9 & ADDR8 */
+       "gpio37", "gpio38",
+       /* ADDR7 - ADDR 0 */
+       "gpio123", "gpio124", "gpio125", "gpio126",
+       "gpio127", "gpio128", "gpio129", "gpio130",
+       /* (muxed address+data) AD15 - AD0 */
+       "gpio135", "gpio136", "gpio137", "gpio138", "gpio139",
+       "gpio140", "gpio141", "gpio142", "gpio143", "gpio144",
+       "gpio145", "gpio146", "gpio147", "gpio148", "gpio149",
+       "gpio150",
+       "gpio151", /* OE output enable */
+       "gpio152", /* clock */
+       "gpio153", /* ADV */
+       "gpio154", /* WAIT (input) */
+       "gpio155", /* UB Upper Byte Enable */
+       "gpio156", /* LB Lower Byte Enable */
+       "gpio157", /* WE Write Enable */
+       "gpio158", /* busy */
+};
 
 static const struct msm_function msm8660_functions[] = {
        FUNCTION(gpio),
@@ -749,6 +781,8 @@ static const struct msm_function msm8660_functions[] = {
        FUNCTION(usb_fs2_oe_n),
        FUNCTION(vfe),
        FUNCTION(vsens_alarm),
+       FUNCTION(ebi2cs), /* for EBI2 chip selects */
+       FUNCTION(ebi2), /* for general EBI2 pins */
 };
 
 static const struct msm_pingroup msm8660_groups[] = {
@@ -789,10 +823,10 @@ static const struct msm_pingroup msm8660_groups[] = {
        PINGROUP(34, gsbi1, _, _, _, _, _, _),
        PINGROUP(35, gsbi1, _, _, _, _, _, _),
        PINGROUP(36, gsbi1, _, _, _, _, _, _),
-       PINGROUP(37, gsbi2, _, _, _, _, _, _),
-       PINGROUP(38, gsbi2, _, _, _, _, _, _),
-       PINGROUP(39, gsbi2, _, mdp_vsync, _, _, _, _),
-       PINGROUP(40, gsbi2, _, _, _, _, _, _),
+       PINGROUP(37, gsbi2, ebi2, _, _, _, _, _),
+       PINGROUP(38, gsbi2, ebi2, _, _, _, _, _),
+       PINGROUP(39, gsbi2, ebi2cs, mdp_vsync, _, _, _, _),
+       PINGROUP(40, gsbi2, ebi2cs, _, _, _, _, _),
        PINGROUP(41, gsbi3, mdp_vsync, _, _, _, _, _),
        PINGROUP(42, gsbi3, vfe, _, _, _, _, _),
        PINGROUP(43, gsbi3, _, _, _, _, _, _),
@@ -875,42 +909,42 @@ static const struct msm_pingroup msm8660_groups[] = {
        PINGROUP(120, i2s, _, _, _, _, _, _),
        PINGROUP(121, i2s, _, _, _, _, _, _),
        PINGROUP(122, i2s, gp_clk_1b, _, _, _, _, _),
-       PINGROUP(123, _, gsbi2_spi_cs1_n, _, _, _, _, _),
-       PINGROUP(124, _, gsbi2_spi_cs2_n, _, _, _, _, _),
-       PINGROUP(125, _, gsbi2_spi_cs3_n, _, _, _, _, _),
-       PINGROUP(126, _, _, _, _, _, _, _),
-       PINGROUP(127, _, vsens_alarm, _, _, _, _, _),
-       PINGROUP(128, _, _, _, _, _, _, _),
-       PINGROUP(129, _, _, _, _, _, _, _),
-       PINGROUP(130, _, _, _, _, _, _, _),
-       PINGROUP(131, _, _, _, _, _, _, _),
-       PINGROUP(132, _, _, _, _, _, _, _),
-       PINGROUP(133, _, _, _, _, _, _, _),
-       PINGROUP(134, _, _, _, _, _, _, _),
-       PINGROUP(135, _, _, _, _, _, _, _),
-       PINGROUP(136, _, _, _, _, _, _, _),
-       PINGROUP(137, _, _, _, _, _, _, _),
-       PINGROUP(138, _, _, _, _, _, _, _),
-       PINGROUP(139, _, _, _, _, _, _, _),
-       PINGROUP(140, _, _, _, _, _, _, _),
-       PINGROUP(141, _, _, _, _, _, _, _),
-       PINGROUP(142, _, _, _, _, _, _, _),
-       PINGROUP(143, _, sdc2, _, _, _, _, _),
-       PINGROUP(144, _, sdc2, _, _, _, _, _),
-       PINGROUP(145, _, sdc2, _, _, _, _, _),
-       PINGROUP(146, _, sdc2, _, _, _, _, _),
-       PINGROUP(147, _, sdc2, _, _, _, _, _),
-       PINGROUP(148, _, sdc2, _, _, _, _, _),
-       PINGROUP(149, _, sdc2, _, _, _, _, _),
-       PINGROUP(150, _, sdc2, _, _, _, _, _),
-       PINGROUP(151, _, sdc2, _, _, _, _, _),
-       PINGROUP(152, _, sdc2, _, _, _, _, _),
-       PINGROUP(153, _, _, _, _, _, _, _),
-       PINGROUP(154, _, _, _, _, _, _, _),
-       PINGROUP(155, _, _, _, _, _, _, _),
-       PINGROUP(156, _, _, _, _, _, _, _),
-       PINGROUP(157, _, _, _, _, _, _, _),
-       PINGROUP(158, _, _, _, _, _, _, _),
+       PINGROUP(123, ebi2, gsbi2_spi_cs1_n, ebi2cs, _, _, _, _),
+       PINGROUP(124, ebi2, gsbi2_spi_cs2_n, ebi2cs, _, _, _, _),
+       PINGROUP(125, ebi2, gsbi2_spi_cs3_n, _, _, _, _, _),
+       PINGROUP(126, ebi2, _, _, _, _, _, _),
+       PINGROUP(127, ebi2, vsens_alarm, _, _, _, _, _),
+       PINGROUP(128, ebi2, _, _, _, _, _, _),
+       PINGROUP(129, ebi2, _, _, _, _, _, _),
+       PINGROUP(130, ebi2, _, _, _, _, _, _),
+       PINGROUP(131, ebi2cs, _, _, _, _, _, _),
+       PINGROUP(132, ebi2cs, _, _, _, _, _, _),
+       PINGROUP(133, ebi2cs, _, _, _, _, _, _),
+       PINGROUP(134, ebi2cs, _, _, _, _, _, _),
+       PINGROUP(135, ebi2, _, _, _, _, _, _),
+       PINGROUP(136, ebi2, _, _, _, _, _, _),
+       PINGROUP(137, ebi2, _, _, _, _, _, _),
+       PINGROUP(138, ebi2, _, _, _, _, _, _),
+       PINGROUP(139, ebi2, _, _, _, _, _, _),
+       PINGROUP(140, ebi2, _, _, _, _, _, _),
+       PINGROUP(141, ebi2, _, _, _, _, _, _),
+       PINGROUP(142, ebi2, _, _, _, _, _, _),
+       PINGROUP(143, ebi2, sdc2, _, _, _, _, _),
+       PINGROUP(144, ebi2, sdc2, _, _, _, _, _),
+       PINGROUP(145, ebi2, sdc2, _, _, _, _, _),
+       PINGROUP(146, ebi2, sdc2, _, _, _, _, _),
+       PINGROUP(147, ebi2, sdc2, _, _, _, _, _),
+       PINGROUP(148, ebi2, sdc2, _, _, _, _, _),
+       PINGROUP(149, ebi2, sdc2, _, _, _, _, _),
+       PINGROUP(150, ebi2, sdc2, _, _, _, _, _),
+       PINGROUP(151, ebi2, sdc2, _, _, _, _, _),
+       PINGROUP(152, ebi2, sdc2, _, _, _, _, _),
+       PINGROUP(153, ebi2, _, _, _, _, _, _),
+       PINGROUP(154, ebi2, _, _, _, _, _, _),
+       PINGROUP(155, ebi2, _, _, _, _, _, _),
+       PINGROUP(156, ebi2, _, _, _, _, _, _),
+       PINGROUP(157, ebi2, _, _, _, _, _, _),
+       PINGROUP(158, ebi2, _, _, _, _, _, _),
        PINGROUP(159, sdc1, _, _, _, _, _, _),
        PINGROUP(160, sdc1, _, _, _, _, _, _),
        PINGROUP(161, sdc1, _, _, _, _, _, _),
index 46fe6ad..9eb63d3 100644 (file)
@@ -172,6 +172,8 @@ static const struct pinctrl_pin_desc msm8x74_pins[] = {
        PINCTRL_PIN(149, "SDC2_CLK"),
        PINCTRL_PIN(150, "SDC2_CMD"),
        PINCTRL_PIN(151, "SDC2_DATA"),
+       PINCTRL_PIN(152, "HSIC_STROBE"),
+       PINCTRL_PIN(153, "HSIC_DATA"),
 };
 
 #define DECLARE_MSM_GPIO_PINS(pin) static const unsigned int gpio##pin##_pins[] = { pin }
@@ -328,6 +330,8 @@ static const unsigned int sdc1_data_pins[] = { 148 };
 static const unsigned int sdc2_clk_pins[] = { 149 };
 static const unsigned int sdc2_cmd_pins[] = { 150 };
 static const unsigned int sdc2_data_pins[] = { 151 };
+static const unsigned int hsic_strobe_pins[] = { 152 };
+static const unsigned int hsic_data_pins[] = { 153 };
 
 #define FUNCTION(fname)                                        \
        [MSM_MUX_##fname] = {                           \
@@ -399,6 +403,37 @@ static const unsigned int sdc2_data_pins[] = { 151 };
                .intr_detection_width = -1,             \
        }
 
+#define HSIC_PINGROUP(pg_name, ctl)                    \
+       {                                               \
+               .name = #pg_name,                       \
+               .pins = pg_name##_pins,                 \
+               .npins = ARRAY_SIZE(pg_name##_pins),    \
+               .funcs = (int[]){                       \
+                       MSM_MUX_gpio,                   \
+                       MSM_MUX_hsic_ctl,               \
+               },                                      \
+               .nfuncs = 2,                            \
+               .ctl_reg = ctl,                         \
+               .io_reg = 0,                            \
+               .intr_cfg_reg = 0,                      \
+               .intr_status_reg = 0,                   \
+               .intr_target_reg = 0,                   \
+               .mux_bit = 25,                          \
+               .pull_bit = -1,                         \
+               .drv_bit = -1,                          \
+               .oe_bit = -1,                           \
+               .in_bit = -1,                           \
+               .out_bit = -1,                          \
+               .intr_enable_bit = -1,                  \
+               .intr_status_bit = -1,                  \
+               .intr_target_bit = -1,                  \
+               .intr_target_kpss_val = -1,             \
+               .intr_raw_status_bit = -1,              \
+               .intr_polarity_bit = -1,                \
+               .intr_detection_bit = -1,               \
+               .intr_detection_width = -1,             \
+       }
+
 /*
  * TODO: Add the rest of the possible functions and fill out
  * the pingroup table below.
@@ -509,6 +544,7 @@ enum msm8x74_functions {
        MSM_MUX_fm,
        MSM_MUX_wlan,
        MSM_MUX_slimbus,
+       MSM_MUX_hsic_ctl,
        MSM_MUX_NA,
 };
 
@@ -534,7 +570,8 @@ static const char * const gpio_groups[] = {
        "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128",
        "gpio129", "gpio130", "gpio131", "gpio132", "gpio133", "gpio134",
        "gpio135", "gpio136", "gpio137", "gpio138", "gpio139", "gpio140",
-       "gpio141", "gpio142", "gpio143", "gpio144", "gpio145"
+       "gpio141", "gpio142", "gpio143", "gpio144", "gpio145", "hsic_data",
+       "hsic_strobe",
 };
 
 static const char * const blsp_uart1_groups[] = {
@@ -754,6 +791,7 @@ static const char * const wlan_groups[] = {
 };
 
 static const char * const slimbus_groups[] = { "gpio70", "gpio71" };
+static const char * const hsic_ctl_groups[] = { "hsic_strobe", "hsic_data" };
 
 static const struct msm_function msm8x74_functions[] = {
        FUNCTION(gpio),
@@ -861,6 +899,7 @@ static const struct msm_function msm8x74_functions[] = {
        FUNCTION(fm),
        FUNCTION(wlan),
        FUNCTION(slimbus),
+       FUNCTION(hsic_ctl),
 };
 
 static const struct msm_pingroup msm8x74_groups[] = {
@@ -1016,6 +1055,8 @@ static const struct msm_pingroup msm8x74_groups[] = {
        SDC_PINGROUP(sdc2_clk, 0x2048, 14, 6),
        SDC_PINGROUP(sdc2_cmd, 0x2048, 11, 3),
        SDC_PINGROUP(sdc2_data, 0x2048, 9, 0),
+       HSIC_PINGROUP(hsic_strobe, 0x2050),
+       HSIC_PINGROUP(hsic_data, 0x2054),
 };
 
 #define NUM_GPIO_PINGROUPS 146
index 9191727..0d1392f 100644 (file)
@@ -744,6 +744,7 @@ static int pm8xxx_pin_populate(struct pm8xxx_mpp *pctrl,
 static const struct of_device_id pm8xxx_mpp_of_match[] = {
        { .compatible = "qcom,pm8018-mpp" },
        { .compatible = "qcom,pm8038-mpp" },
+       { .compatible = "qcom,pm8058-mpp" },
        { .compatible = "qcom,pm8917-mpp" },
        { .compatible = "qcom,pm8821-mpp" },
        { .compatible = "qcom,pm8921-mpp" },
index fb71fc3..3000df8 100644 (file)
@@ -998,6 +998,7 @@ static struct platform_driver exynos5440_pinctrl_driver = {
        .driver = {
                .name   = "exynos5440-pinctrl",
                .of_match_table = exynos5440_pinctrl_dt_match,
+               .suppress_bind_attrs = true,
        },
 };
 
index ed0b708..513fe6b 100644 (file)
@@ -1274,6 +1274,7 @@ static struct platform_driver samsung_pinctrl_driver = {
        .driver = {
                .name   = "samsung-pinctrl",
                .of_match_table = samsung_pinctrl_dt_match,
+               .suppress_bind_attrs = true,
        },
 };
 
index 9b9cee0..a3b8204 100644 (file)
@@ -598,15 +598,6 @@ static int sh_pfc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int sh_pfc_remove(struct platform_device *pdev)
-{
-#ifdef CONFIG_PINCTRL_SH_PFC_GPIO
-       sh_pfc_unregister_gpiochip(platform_get_drvdata(pdev));
-#endif
-
-       return 0;
-}
-
 static const struct platform_device_id sh_pfc_id_table[] = {
 #ifdef CONFIG_PINCTRL_PFC_SH7203
        { "pfc-sh7203", (kernel_ulong_t)&sh7203_pinmux_info },
@@ -650,7 +641,6 @@ static const struct platform_device_id sh_pfc_id_table[] = {
 
 static struct platform_driver sh_pfc_driver = {
        .probe          = sh_pfc_probe,
-       .remove         = sh_pfc_remove,
        .id_table       = sh_pfc_id_table,
        .driver         = {
                .name   = DRV_NAME,
index dc1b2ad..0bbdea5 100644 (file)
 #ifndef __SH_PFC_CORE_H__
 #define __SH_PFC_CORE_H__
 
-#include <linux/compiler.h>
-#include <linux/spinlock.h>
 #include <linux/types.h>
 
 #include "sh_pfc.h"
 
-struct sh_pfc_window {
-       phys_addr_t phys;
-       void __iomem *virt;
-       unsigned long size;
-};
-
-struct sh_pfc_chip;
-struct sh_pfc_pinctrl;
-
 struct sh_pfc_pin_range {
        u16 start;
        u16 end;
 };
 
-struct sh_pfc {
-       struct device *dev;
-       const struct sh_pfc_soc_info *info;
-       spinlock_t lock;
-
-       unsigned int num_windows;
-       struct sh_pfc_window *windows;
-       unsigned int num_irqs;
-       unsigned int *irqs;
-
-       struct sh_pfc_pin_range *ranges;
-       unsigned int nr_ranges;
-
-       unsigned int nr_gpio_pins;
-
-       struct sh_pfc_chip *gpio;
-#ifdef CONFIG_SUPERH
-       struct sh_pfc_chip *func;
-#endif
-
-};
-
 int sh_pfc_register_gpiochip(struct sh_pfc *pfc);
-int sh_pfc_unregister_gpiochip(struct sh_pfc *pfc);
 
 int sh_pfc_register_pinctrl(struct sh_pfc *pfc);
 
@@ -67,28 +33,4 @@ void sh_pfc_write_reg(struct sh_pfc *pfc, u32 reg, unsigned int width,
 int sh_pfc_get_pin_index(struct sh_pfc *pfc, unsigned int pin);
 int sh_pfc_config_mux(struct sh_pfc *pfc, unsigned mark, int pinmux_type);
 
-extern const struct sh_pfc_soc_info emev2_pinmux_info;
-extern const struct sh_pfc_soc_info r8a73a4_pinmux_info;
-extern const struct sh_pfc_soc_info r8a7740_pinmux_info;
-extern const struct sh_pfc_soc_info r8a7778_pinmux_info;
-extern const struct sh_pfc_soc_info r8a7779_pinmux_info;
-extern const struct sh_pfc_soc_info r8a7790_pinmux_info;
-extern const struct sh_pfc_soc_info r8a7791_pinmux_info;
-extern const struct sh_pfc_soc_info r8a7793_pinmux_info;
-extern const struct sh_pfc_soc_info r8a7794_pinmux_info;
-extern const struct sh_pfc_soc_info r8a7795_pinmux_info;
-extern const struct sh_pfc_soc_info sh7203_pinmux_info;
-extern const struct sh_pfc_soc_info sh7264_pinmux_info;
-extern const struct sh_pfc_soc_info sh7269_pinmux_info;
-extern const struct sh_pfc_soc_info sh73a0_pinmux_info;
-extern const struct sh_pfc_soc_info sh7720_pinmux_info;
-extern const struct sh_pfc_soc_info sh7722_pinmux_info;
-extern const struct sh_pfc_soc_info sh7723_pinmux_info;
-extern const struct sh_pfc_soc_info sh7724_pinmux_info;
-extern const struct sh_pfc_soc_info sh7734_pinmux_info;
-extern const struct sh_pfc_soc_info sh7757_pinmux_info;
-extern const struct sh_pfc_soc_info sh7785_pinmux_info;
-extern const struct sh_pfc_soc_info sh7786_pinmux_info;
-extern const struct sh_pfc_soc_info shx3_pinmux_info;
-
 #endif /* __SH_PFC_CORE_H__ */
index 97dff6a..6b54227 100644 (file)
@@ -318,7 +318,7 @@ sh_pfc_add_gpiochip(struct sh_pfc *pfc, int(*setup)(struct sh_pfc_chip *),
        if (ret < 0)
                return ERR_PTR(ret);
 
-       ret = gpiochip_add_data(&chip->gpio_chip, chip);
+       ret = devm_gpiochip_add_data(pfc->dev, &chip->gpio_chip, chip);
        if (unlikely(ret < 0))
                return ERR_PTR(ret);
 
@@ -399,18 +399,7 @@ int sh_pfc_register_gpiochip(struct sh_pfc *pfc)
        chip = sh_pfc_add_gpiochip(pfc, gpio_function_setup, NULL);
        if (IS_ERR(chip))
                return PTR_ERR(chip);
-
-       pfc->func = chip;
 #endif /* CONFIG_SUPERH */
 
        return 0;
 }
-
-int sh_pfc_unregister_gpiochip(struct sh_pfc *pfc)
-{
-       gpiochip_remove(&pfc->gpio->gpio_chip);
-#ifdef CONFIG_SUPERH
-       gpiochip_remove(&pfc->func->gpio_chip);
-#endif
-       return 0;
-}
index d9d9228..ff5655d 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/kernel.h>
 #include <linux/pinctrl/pinconf-generic.h>
 
-#include "core.h"
 #include "sh_pfc.h"
 
 #define CPU_ALL_PORT(fn, pfx, sfx)                                     \
index 7f7c8a6..35f436b 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/kernel.h>
 #include <linux/pinctrl/pinconf-generic.h>
 
-#include "core.h"
 #include "sh_pfc.h"
 
 #define CPU_ALL_PORT(fn, pfx, sfx)                                     \
index 411d088..18ef704 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/pinctrl/pinconf-generic.h>
-#include "core.h"
+
 #include "sh_pfc.h"
 
 #define PORT_GP_PUP_1(bank, pin, fn, sfx)      \
index eed8daa..b769c05 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/io.h>
 #include <linux/kernel.h>
 
-#include "core.h"
 #include "sh_pfc.h"
 
 /*
@@ -4696,47 +4695,6 @@ static const char * const vin3_groups[] = {
        "vin3_clk",
 };
 
-#define IOCTRL6 0x8c
-
-static int r8a7790_get_io_voltage(struct sh_pfc *pfc, unsigned int pin)
-{
-       u32 data, mask;
-
-       if (WARN(pin < RCAR_GP_PIN(3, 0) || pin > RCAR_GP_PIN(3, 31), "invalid pin %#x", pin))
-               return -EINVAL;
-
-       data = ioread32(pfc->windows->virt + IOCTRL6),
-       /* Bits in IOCTRL6 are numbered in opposite order to pins */
-       mask = 0x80000000 >> (pin & 0x1f);
-
-       return (data & mask) ? 3300 : 1800;
-}
-
-static int r8a7790_set_io_voltage(struct sh_pfc *pfc, unsigned int pin, u16 mV)
-{
-       u32 data, mask;
-
-       if (WARN(pin < RCAR_GP_PIN(3, 0) || pin > RCAR_GP_PIN(3, 31), "invalid pin %#x", pin))
-               return -EINVAL;
-
-       if (mV != 1800 && mV != 3300)
-               return -EINVAL;
-
-       data = ioread32(pfc->windows->virt + IOCTRL6);
-       /* Bits in IOCTRL6 are numbered in opposite order to pins */
-       mask = 0x80000000 >> (pin & 0x1f);
-
-       if (mV == 3300)
-               data |= mask;
-       else
-               data &= ~mask;
-
-       iowrite32(~data, pfc->windows->virt); /* unlock reg */
-       iowrite32(data, pfc->windows->virt + IOCTRL6);
-
-       return 0;
-}
-
 static const struct sh_pfc_function pinmux_functions[] = {
        SH_PFC_FUNCTION(audio_clk),
        SH_PFC_FUNCTION(avb),
@@ -5736,14 +5694,23 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
        { },
 };
 
-static const struct sh_pfc_soc_operations pinmux_ops = {
-       .get_io_voltage = r8a7790_get_io_voltage,
-       .set_io_voltage = r8a7790_set_io_voltage,
+static int r8a7790_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *pocctrl)
+{
+       if (pin < RCAR_GP_PIN(3, 0) || pin > RCAR_GP_PIN(3, 31))
+               return -EINVAL;
+
+       *pocctrl = 0xe606008c;
+
+       return 31 - (pin & 0x1f);
+}
+
+static const struct sh_pfc_soc_operations r8a7790_pinmux_ops = {
+       .pin_to_pocctrl = r8a7790_pin_to_pocctrl,
 };
 
 const struct sh_pfc_soc_info r8a7790_pinmux_info = {
        .name = "r8a77900_pfc",
-       .ops = &pinmux_ops,
+       .ops = &r8a7790_pinmux_ops,
        .unlock_reg = 0xe6060000, /* PMMR */
 
        .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
index 01abbd5..0c1a60c 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/kernel.h>
 
-#include "core.h"
 #include "sh_pfc.h"
 
 #define CPU_ALL_PORT(fn, sfx)                                          \
index 44632b1..b74cdd3 100644 (file)
        PORT_GP_CFG_16(0, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),      \
        PORT_GP_CFG_28(1, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),      \
        PORT_GP_CFG_15(2, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),      \
-       PORT_GP_CFG_16(3, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),      \
-       PORT_GP_CFG_18(4, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),      \
+       PORT_GP_CFG_12(3, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_IO_VOLTAGE),  \
+       PORT_GP_CFG_1(3, 12, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),   \
+       PORT_GP_CFG_1(3, 13, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),   \
+       PORT_GP_CFG_1(3, 14, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),   \
+       PORT_GP_CFG_1(3, 15, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),   \
+       PORT_GP_CFG_18(4, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_IO_VOLTAGE),  \
        PORT_GP_CFG_26(5, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),      \
        PORT_GP_CFG_32(6, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH),      \
        PORT_GP_CFG_4(7, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH)
@@ -552,6 +556,9 @@ static const u16 pinmux_data[] = {
        PINMUX_SINGLE(AVS2),
        PINMUX_SINGLE(HDMI0_CEC),
        PINMUX_SINGLE(HDMI1_CEC),
+       PINMUX_SINGLE(I2C_SEL_0_1),
+       PINMUX_SINGLE(I2C_SEL_3_1),
+       PINMUX_SINGLE(I2C_SEL_5_1),
        PINMUX_SINGLE(MSIOF0_RXD),
        PINMUX_SINGLE(MSIOF0_SCK),
        PINMUX_SINGLE(MSIOF0_TXD),
@@ -1401,11 +1408,6 @@ static const u16 pinmux_data[] = {
        PINMUX_IPSR_MSEL(IP17_7_4,      STP_ISSYNC_0_E,         SEL_SSP1_0_4),
        PINMUX_IPSR_MSEL(IP17_7_4,      RIF2_D1_B,              SEL_DRIF2_1),
        PINMUX_IPSR_GPSR(IP17_7_4,      TPU0TO3),
-
-       /* I2C */
-       PINMUX_IPSR_NOGP(0,             I2C_SEL_0_1),
-       PINMUX_IPSR_NOGP(0,             I2C_SEL_3_1),
-       PINMUX_IPSR_NOGP(0,             I2C_SEL_5_1),
 };
 
 static const struct sh_pfc_pin pinmux_pins[] = {
@@ -1654,6 +1656,221 @@ static const unsigned int canfd1_data_mux[] = {
        CANFD1_TX_MARK,         CANFD1_RX_MARK,
 };
 
+/* - DRIF0 --------------------------------------------------------------- */
+static const unsigned int drif0_ctrl_a_pins[] = {
+       /* CLK, SYNC */
+       RCAR_GP_PIN(6, 8), RCAR_GP_PIN(6, 9),
+};
+static const unsigned int drif0_ctrl_a_mux[] = {
+       RIF0_CLK_A_MARK, RIF0_SYNC_A_MARK,
+};
+static const unsigned int drif0_data0_a_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(6, 10),
+};
+static const unsigned int drif0_data0_a_mux[] = {
+       RIF0_D0_A_MARK,
+};
+static const unsigned int drif0_data1_a_pins[] = {
+       /* D1 */
+       RCAR_GP_PIN(6, 7),
+};
+static const unsigned int drif0_data1_a_mux[] = {
+       RIF0_D1_A_MARK,
+};
+static const unsigned int drif0_ctrl_b_pins[] = {
+       /* CLK, SYNC */
+       RCAR_GP_PIN(5, 0), RCAR_GP_PIN(5, 4),
+};
+static const unsigned int drif0_ctrl_b_mux[] = {
+       RIF0_CLK_B_MARK, RIF0_SYNC_B_MARK,
+};
+static const unsigned int drif0_data0_b_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(5, 1),
+};
+static const unsigned int drif0_data0_b_mux[] = {
+       RIF0_D0_B_MARK,
+};
+static const unsigned int drif0_data1_b_pins[] = {
+       /* D1 */
+       RCAR_GP_PIN(5, 2),
+};
+static const unsigned int drif0_data1_b_mux[] = {
+       RIF0_D1_B_MARK,
+};
+static const unsigned int drif0_ctrl_c_pins[] = {
+       /* CLK, SYNC */
+       RCAR_GP_PIN(5, 12), RCAR_GP_PIN(5, 15),
+};
+static const unsigned int drif0_ctrl_c_mux[] = {
+       RIF0_CLK_C_MARK, RIF0_SYNC_C_MARK,
+};
+static const unsigned int drif0_data0_c_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(5, 13),
+};
+static const unsigned int drif0_data0_c_mux[] = {
+       RIF0_D0_C_MARK,
+};
+static const unsigned int drif0_data1_c_pins[] = {
+       /* D1 */
+       RCAR_GP_PIN(5, 14),
+};
+static const unsigned int drif0_data1_c_mux[] = {
+       RIF0_D1_C_MARK,
+};
+/* - DRIF1 --------------------------------------------------------------- */
+static const unsigned int drif1_ctrl_a_pins[] = {
+       /* CLK, SYNC */
+       RCAR_GP_PIN(6, 17), RCAR_GP_PIN(6, 18),
+};
+static const unsigned int drif1_ctrl_a_mux[] = {
+       RIF1_CLK_A_MARK, RIF1_SYNC_A_MARK,
+};
+static const unsigned int drif1_data0_a_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(6, 19),
+};
+static const unsigned int drif1_data0_a_mux[] = {
+       RIF1_D0_A_MARK,
+};
+static const unsigned int drif1_data1_a_pins[] = {
+       /* D1 */
+       RCAR_GP_PIN(6, 20),
+};
+static const unsigned int drif1_data1_a_mux[] = {
+       RIF1_D1_A_MARK,
+};
+static const unsigned int drif1_ctrl_b_pins[] = {
+       /* CLK, SYNC */
+       RCAR_GP_PIN(5, 9), RCAR_GP_PIN(5, 3),
+};
+static const unsigned int drif1_ctrl_b_mux[] = {
+       RIF1_CLK_B_MARK, RIF1_SYNC_B_MARK,
+};
+static const unsigned int drif1_data0_b_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(5, 7),
+};
+static const unsigned int drif1_data0_b_mux[] = {
+       RIF1_D0_B_MARK,
+};
+static const unsigned int drif1_data1_b_pins[] = {
+       /* D1 */
+       RCAR_GP_PIN(5, 8),
+};
+static const unsigned int drif1_data1_b_mux[] = {
+       RIF1_D1_B_MARK,
+};
+static const unsigned int drif1_ctrl_c_pins[] = {
+       /* CLK, SYNC */
+       RCAR_GP_PIN(5, 5), RCAR_GP_PIN(5, 11),
+};
+static const unsigned int drif1_ctrl_c_mux[] = {
+       RIF1_CLK_C_MARK, RIF1_SYNC_C_MARK,
+};
+static const unsigned int drif1_data0_c_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(5, 6),
+};
+static const unsigned int drif1_data0_c_mux[] = {
+       RIF1_D0_C_MARK,
+};
+static const unsigned int drif1_data1_c_pins[] = {
+       /* D1 */
+       RCAR_GP_PIN(5, 10),
+};
+static const unsigned int drif1_data1_c_mux[] = {
+       RIF1_D1_C_MARK,
+};
+/* - DRIF2 --------------------------------------------------------------- */
+static const unsigned int drif2_ctrl_a_pins[] = {
+       /* CLK, SYNC */
+       RCAR_GP_PIN(6, 8), RCAR_GP_PIN(6, 9),
+};
+static const unsigned int drif2_ctrl_a_mux[] = {
+       RIF2_CLK_A_MARK, RIF2_SYNC_A_MARK,
+};
+static const unsigned int drif2_data0_a_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(6, 7),
+};
+static const unsigned int drif2_data0_a_mux[] = {
+       RIF2_D0_A_MARK,
+};
+static const unsigned int drif2_data1_a_pins[] = {
+       /* D1 */
+       RCAR_GP_PIN(6, 10),
+};
+static const unsigned int drif2_data1_a_mux[] = {
+       RIF2_D1_A_MARK,
+};
+static const unsigned int drif2_ctrl_b_pins[] = {
+       /* CLK, SYNC */
+       RCAR_GP_PIN(6, 26), RCAR_GP_PIN(6, 27),
+};
+static const unsigned int drif2_ctrl_b_mux[] = {
+       RIF2_CLK_B_MARK, RIF2_SYNC_B_MARK,
+};
+static const unsigned int drif2_data0_b_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(6, 30),
+};
+static const unsigned int drif2_data0_b_mux[] = {
+       RIF2_D0_B_MARK,
+};
+static const unsigned int drif2_data1_b_pins[] = {
+       /* D1 */
+       RCAR_GP_PIN(6, 31),
+};
+static const unsigned int drif2_data1_b_mux[] = {
+       RIF2_D1_B_MARK,
+};
+/* - DRIF3 --------------------------------------------------------------- */
+static const unsigned int drif3_ctrl_a_pins[] = {
+       /* CLK, SYNC */
+       RCAR_GP_PIN(6, 17), RCAR_GP_PIN(6, 18),
+};
+static const unsigned int drif3_ctrl_a_mux[] = {
+       RIF3_CLK_A_MARK, RIF3_SYNC_A_MARK,
+};
+static const unsigned int drif3_data0_a_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(6, 19),
+};
+static const unsigned int drif3_data0_a_mux[] = {
+       RIF3_D0_A_MARK,
+};
+static const unsigned int drif3_data1_a_pins[] = {
+       /* D1 */
+       RCAR_GP_PIN(6, 20),
+};
+static const unsigned int drif3_data1_a_mux[] = {
+       RIF3_D1_A_MARK,
+};
+static const unsigned int drif3_ctrl_b_pins[] = {
+       /* CLK, SYNC */
+       RCAR_GP_PIN(6, 24), RCAR_GP_PIN(6, 25),
+};
+static const unsigned int drif3_ctrl_b_mux[] = {
+       RIF3_CLK_B_MARK, RIF3_SYNC_B_MARK,
+};
+static const unsigned int drif3_data0_b_pins[] = {
+       /* D0 */
+       RCAR_GP_PIN(6, 28),
+};
+static const unsigned int drif3_data0_b_mux[] = {
+       RIF3_D0_B_MARK,
+};
+static const unsigned int drif3_data1_b_pins[] = {
+       /* D1 */
+       RCAR_GP_PIN(6, 29),
+};
+static const unsigned int drif3_data1_b_mux[] = {
+       RIF3_D1_B_MARK,
+};
+
 /* - HSCIF0 ----------------------------------------------------------------- */
 static const unsigned int hscif0_data_pins[] = {
        /* RX, TX */
@@ -3346,6 +3563,36 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(canfd0_data_a),
        SH_PFC_PIN_GROUP(canfd0_data_b),
        SH_PFC_PIN_GROUP(canfd1_data),
+       SH_PFC_PIN_GROUP(drif0_ctrl_a),
+       SH_PFC_PIN_GROUP(drif0_data0_a),
+       SH_PFC_PIN_GROUP(drif0_data1_a),
+       SH_PFC_PIN_GROUP(drif0_ctrl_b),
+       SH_PFC_PIN_GROUP(drif0_data0_b),
+       SH_PFC_PIN_GROUP(drif0_data1_b),
+       SH_PFC_PIN_GROUP(drif0_ctrl_c),
+       SH_PFC_PIN_GROUP(drif0_data0_c),
+       SH_PFC_PIN_GROUP(drif0_data1_c),
+       SH_PFC_PIN_GROUP(drif1_ctrl_a),
+       SH_PFC_PIN_GROUP(drif1_data0_a),
+       SH_PFC_PIN_GROUP(drif1_data1_a),
+       SH_PFC_PIN_GROUP(drif1_ctrl_b),
+       SH_PFC_PIN_GROUP(drif1_data0_b),
+       SH_PFC_PIN_GROUP(drif1_data1_b),
+       SH_PFC_PIN_GROUP(drif1_ctrl_c),
+       SH_PFC_PIN_GROUP(drif1_data0_c),
+       SH_PFC_PIN_GROUP(drif1_data1_c),
+       SH_PFC_PIN_GROUP(drif2_ctrl_a),
+       SH_PFC_PIN_GROUP(drif2_data0_a),
+       SH_PFC_PIN_GROUP(drif2_data1_a),
+       SH_PFC_PIN_GROUP(drif2_ctrl_b),
+       SH_PFC_PIN_GROUP(drif2_data0_b),
+       SH_PFC_PIN_GROUP(drif2_data1_b),
+       SH_PFC_PIN_GROUP(drif3_ctrl_a),
+       SH_PFC_PIN_GROUP(drif3_data0_a),
+       SH_PFC_PIN_GROUP(drif3_data1_a),
+       SH_PFC_PIN_GROUP(drif3_ctrl_b),
+       SH_PFC_PIN_GROUP(drif3_data0_b),
+       SH_PFC_PIN_GROUP(drif3_data1_b),
        SH_PFC_PIN_GROUP(hscif0_data),
        SH_PFC_PIN_GROUP(hscif0_clk),
        SH_PFC_PIN_GROUP(hscif0_ctrl),
@@ -3629,6 +3876,48 @@ static const char * const canfd1_groups[] = {
        "canfd1_data",
 };
 
+static const char * const drif0_groups[] = {
+       "drif0_ctrl_a",
+       "drif0_data0_a",
+       "drif0_data1_a",
+       "drif0_ctrl_b",
+       "drif0_data0_b",
+       "drif0_data1_b",
+       "drif0_ctrl_c",
+       "drif0_data0_c",
+       "drif0_data1_c",
+};
+
+static const char * const drif1_groups[] = {
+       "drif1_ctrl_a",
+       "drif1_data0_a",
+       "drif1_data1_a",
+       "drif1_ctrl_b",
+       "drif1_data0_b",
+       "drif1_data1_b",
+       "drif1_ctrl_c",
+       "drif1_data0_c",
+       "drif1_data1_c",
+};
+
+static const char * const drif2_groups[] = {
+       "drif2_ctrl_a",
+       "drif2_data0_a",
+       "drif2_data1_a",
+       "drif2_ctrl_b",
+       "drif2_data0_b",
+       "drif2_data1_b",
+};
+
+static const char * const drif3_groups[] = {
+       "drif3_ctrl_a",
+       "drif3_data0_a",
+       "drif3_data1_a",
+       "drif3_ctrl_b",
+       "drif3_data0_b",
+       "drif3_data1_b",
+};
+
 static const char * const hscif0_groups[] = {
        "hscif0_data",
        "hscif0_clk",
@@ -3972,6 +4261,10 @@ static const struct sh_pfc_function pinmux_functions[] = {
        SH_PFC_FUNCTION(can_clk),
        SH_PFC_FUNCTION(canfd0),
        SH_PFC_FUNCTION(canfd1),
+       SH_PFC_FUNCTION(drif0),
+       SH_PFC_FUNCTION(drif1),
+       SH_PFC_FUNCTION(drif2),
+       SH_PFC_FUNCTION(drif3),
        SH_PFC_FUNCTION(hscif0),
        SH_PFC_FUNCTION(hscif1),
        SH_PFC_FUNCTION(hscif2),
@@ -4765,8 +5058,28 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
        { },
 };
 
+static int r8a7795_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *pocctrl)
+{
+       int bit = -EINVAL;
+
+       *pocctrl = 0xe6060380;
+
+       if (pin >= RCAR_GP_PIN(3, 0) && pin <= RCAR_GP_PIN(3, 11))
+               bit = pin & 0x1f;
+
+       if (pin >= RCAR_GP_PIN(4, 0) && pin <= RCAR_GP_PIN(4, 17))
+               bit = (pin & 0x1f) + 12;
+
+       return bit;
+}
+
+static const struct sh_pfc_soc_operations r8a7795_pinmux_ops = {
+       .pin_to_pocctrl = r8a7795_pin_to_pocctrl,
+};
+
 const struct sh_pfc_soc_info r8a7795_pinmux_info = {
        .name = "r8a77950_pfc",
+       .ops = &r8a7795_pinmux_ops,
        .unlock_reg = 0xe6060000, /* PMMR */
 
        .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
index 0555a1f..6d8c31c 100644 (file)
@@ -1625,7 +1625,6 @@ static const struct pinmux_func pinmux_func_gpios[] = {
        GPIO_FN(VBIOS_CS),
 
        /* PTW (mobule: LBSC, EVC, SCIF) */
-       GPIO_FN(A16),
        GPIO_FN(A15),
        GPIO_FN(A14),
        GPIO_FN(A13),
index fdb445d..e208ee0 100644 (file)
@@ -632,19 +632,21 @@ static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned _pin,
        }
 
        case PIN_CONFIG_POWER_SOURCE: {
-               int ret;
+               u32 pocctrl, val;
+               int bit;
 
-               if (!pfc->info->ops || !pfc->info->ops->get_io_voltage)
+               if (!pfc->info->ops || !pfc->info->ops->pin_to_pocctrl)
                        return -ENOTSUPP;
 
+               bit = pfc->info->ops->pin_to_pocctrl(pfc, _pin, &pocctrl);
+               if (WARN(bit < 0, "invalid pin %#x", _pin))
+                       return bit;
+
                spin_lock_irqsave(&pfc->lock, flags);
-               ret = pfc->info->ops->get_io_voltage(pfc, _pin);
+               val = sh_pfc_read_reg(pfc, pocctrl, 32);
                spin_unlock_irqrestore(&pfc->lock, flags);
 
-               if (ret < 0)
-                       return ret;
-
-               *config = ret;
+               *config = (val & BIT(bit)) ? 3300 : 1800;
                break;
        }
 
@@ -696,20 +698,29 @@ static int sh_pfc_pinconf_set(struct pinctrl_dev *pctldev, unsigned _pin,
                }
 
                case PIN_CONFIG_POWER_SOURCE: {
-                       unsigned int arg =
-                               pinconf_to_config_argument(configs[i]);
-                       int ret;
+                       unsigned int mV = pinconf_to_config_argument(configs[i]);
+                       u32 pocctrl, val;
+                       int bit;
 
-                       if (!pfc->info->ops || !pfc->info->ops->set_io_voltage)
+                       if (!pfc->info->ops || !pfc->info->ops->pin_to_pocctrl)
                                return -ENOTSUPP;
 
+                       bit = pfc->info->ops->pin_to_pocctrl(pfc, _pin, &pocctrl);
+                       if (WARN(bit < 0, "invalid pin %#x", _pin))
+                               return bit;
+
+                       if (mV != 1800 && mV != 3300)
+                               return -EINVAL;
+
                        spin_lock_irqsave(&pfc->lock, flags);
-                       ret = pfc->info->ops->set_io_voltage(pfc, _pin, arg);
+                       val = sh_pfc_read_reg(pfc, pocctrl, 32);
+                       if (mV == 3300)
+                               val |= BIT(bit);
+                       else
+                               val &= ~BIT(bit);
+                       sh_pfc_write_reg(pfc, pocctrl, 32, val);
                        spin_unlock_irqrestore(&pfc->lock, flags);
 
-                       if (ret)
-                               return ret;
-
                        break;
                }
 
@@ -803,8 +814,5 @@ int sh_pfc_register_pinctrl(struct sh_pfc *pfc)
        pmx->pctl_desc.npins = pfc->info->nr_pins;
 
        pmx->pctl = devm_pinctrl_register(pfc->dev, &pmx->pctl_desc, pmx);
-       if (IS_ERR(pmx->pctl))
-               return PTR_ERR(pmx->pctl);
-
-       return 0;
+       return PTR_ERR_OR_ZERO(pmx->pctl);
 }
index 656ea32..5e966c0 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/bug.h>
 #include <linux/pinctrl/pinconf-generic.h>
+#include <linux/spinlock.h>
 #include <linux/stringify.h>
 
 enum {
@@ -182,16 +183,38 @@ struct pinmux_range {
        u16 force;
 };
 
-struct sh_pfc;
+struct sh_pfc_window {
+       phys_addr_t phys;
+       void __iomem *virt;
+       unsigned long size;
+};
+
+struct sh_pfc_pin_range;
+
+struct sh_pfc {
+       struct device *dev;
+       const struct sh_pfc_soc_info *info;
+       spinlock_t lock;
+
+       unsigned int num_windows;
+       struct sh_pfc_window *windows;
+       unsigned int num_irqs;
+       unsigned int *irqs;
+
+       struct sh_pfc_pin_range *ranges;
+       unsigned int nr_ranges;
+
+       unsigned int nr_gpio_pins;
+
+       struct sh_pfc_chip *gpio;
+};
 
 struct sh_pfc_soc_operations {
        int (*init)(struct sh_pfc *pfc);
        unsigned int (*get_bias)(struct sh_pfc *pfc, unsigned int pin);
        void (*set_bias)(struct sh_pfc *pfc, unsigned int pin,
                         unsigned int bias);
-       int (*get_io_voltage)(struct sh_pfc *pfc, unsigned int pin);
-       int (*set_io_voltage)(struct sh_pfc *pfc, unsigned int pin,
-                             u16 voltage_mV);
+       int (*pin_to_pocctrl)(struct sh_pfc *pfc, unsigned int pin, u32 *pocctrl);
 };
 
 struct sh_pfc_soc_info {
@@ -227,6 +250,30 @@ struct sh_pfc_soc_info {
        u32 unlock_reg;
 };
 
+extern const struct sh_pfc_soc_info emev2_pinmux_info;
+extern const struct sh_pfc_soc_info r8a73a4_pinmux_info;
+extern const struct sh_pfc_soc_info r8a7740_pinmux_info;
+extern const struct sh_pfc_soc_info r8a7778_pinmux_info;
+extern const struct sh_pfc_soc_info r8a7779_pinmux_info;
+extern const struct sh_pfc_soc_info r8a7790_pinmux_info;
+extern const struct sh_pfc_soc_info r8a7791_pinmux_info;
+extern const struct sh_pfc_soc_info r8a7793_pinmux_info;
+extern const struct sh_pfc_soc_info r8a7794_pinmux_info;
+extern const struct sh_pfc_soc_info r8a7795_pinmux_info;
+extern const struct sh_pfc_soc_info sh7203_pinmux_info;
+extern const struct sh_pfc_soc_info sh7264_pinmux_info;
+extern const struct sh_pfc_soc_info sh7269_pinmux_info;
+extern const struct sh_pfc_soc_info sh73a0_pinmux_info;
+extern const struct sh_pfc_soc_info sh7720_pinmux_info;
+extern const struct sh_pfc_soc_info sh7722_pinmux_info;
+extern const struct sh_pfc_soc_info sh7723_pinmux_info;
+extern const struct sh_pfc_soc_info sh7724_pinmux_info;
+extern const struct sh_pfc_soc_info sh7734_pinmux_info;
+extern const struct sh_pfc_soc_info sh7757_pinmux_info;
+extern const struct sh_pfc_soc_info sh7785_pinmux_info;
+extern const struct sh_pfc_soc_info sh7786_pinmux_info;
+extern const struct sh_pfc_soc_info shx3_pinmux_info;
+
 /* -----------------------------------------------------------------------------
  * Helper macros to create pin and port lists
  */
index 168c0f5..19952f7 100644 (file)
@@ -5424,8 +5424,10 @@ static int atlas7_pinmux_probe(struct platform_device *pdev)
        if (ret)
                return ret;
        pmx->sys2pci_base = devm_ioremap_resource(&pdev->dev, &res);
-       if (IS_ERR(pmx->sys2pci_base))
+       if (IS_ERR(pmx->sys2pci_base)) {
+               of_node_put(sys2pci_np);
                return -ENOMEM;
+       }
 
        pmx->dev = &pdev->dev;
 
index 0f28841..4c40dae 100644 (file)
@@ -13,4 +13,10 @@ config PINCTRL_STM32F429
        default MACH_STM32F429
        select PINCTRL_STM32
 
+config PINCTRL_STM32F746
+       bool "STMicroelectronics STM32F746 pin control" if COMPILE_TEST && !MACH_STM32F746
+       depends on OF
+       default MACH_STM32F746
+       select PINCTRL_STM32
+
 endif
index fc17d42..4a1ee74 100644 (file)
@@ -3,3 +3,4 @@ obj-$(CONFIG_PINCTRL_STM32) += pinctrl-stm32.o
 
 # SoC Drivers
 obj-$(CONFIG_PINCTRL_STM32F429)        += pinctrl-stm32f429.o
+obj-$(CONFIG_PINCTRL_STM32F746)        += pinctrl-stm32f746.o
index ae9fab8..4ae596b 100644 (file)
@@ -638,8 +638,8 @@ static u32 stm32_pconf_get_bias(struct stm32_gpio_bank *bank,
        return (val >> (offset * 2));
 }
 
-static bool stm32_pconf_input_get(struct stm32_gpio_bank *bank,
-       unsigned int offset)
+static bool stm32_pconf_get(struct stm32_gpio_bank *bank,
+       unsigned int offset, bool dir)
 {
        unsigned long flags;
        u32 val;
@@ -647,23 +647,12 @@ static bool stm32_pconf_input_get(struct stm32_gpio_bank *bank,
        clk_enable(bank->clk);
        spin_lock_irqsave(&bank->lock, flags);
 
-       val = !!(readl_relaxed(bank->base + STM32_GPIO_IDR) & BIT(offset));
-
-       spin_unlock_irqrestore(&bank->lock, flags);
-       clk_disable(bank->clk);
-
-       return val;
-}
-
-static bool stm32_pconf_output_get(struct stm32_gpio_bank *bank,
-       unsigned int offset)
-{
-       unsigned long flags;
-       u32 val;
-
-       clk_enable(bank->clk);
-       spin_lock_irqsave(&bank->lock, flags);
-       val = !!(readl_relaxed(bank->base + STM32_GPIO_ODR) & BIT(offset));
+       if (dir)
+               val = !!(readl_relaxed(bank->base + STM32_GPIO_IDR) &
+                        BIT(offset));
+       else
+               val = !!(readl_relaxed(bank->base + STM32_GPIO_ODR) &
+                        BIT(offset));
 
        spin_unlock_irqrestore(&bank->lock, flags);
        clk_disable(bank->clk);
@@ -772,7 +761,7 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev,
        switch (mode) {
        /* input */
        case 0:
-               val = stm32_pconf_input_get(bank, offset);
+               val = stm32_pconf_get(bank, offset, true);
                seq_printf(s, "- %s - %s",
                           val ? "high" : "low",
                           biasing[bias]);
@@ -782,7 +771,7 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev,
        case 1:
                drive = stm32_pconf_get_driving(bank, offset);
                speed = stm32_pconf_get_speed(bank, offset);
-               val = stm32_pconf_output_get(bank, offset);
+               val = stm32_pconf_get(bank, offset, false);
                seq_printf(s, "- %s - %s - %s - %s %s",
                           val ? "high" : "low",
                           drive ? "open drain" : "push pull",
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32f746.c b/drivers/pinctrl/stm32/pinctrl-stm32f746.c
new file mode 100644 (file)
index 0000000..c0b4462
--- /dev/null
@@ -0,0 +1,1681 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-stm32.h"
+
+static const struct stm32_desc_pin stm32f746_pins[] = {
+       STM32_PIN(
+               PINCTRL_PIN(0, "PA0"),
+               STM32_FUNCTION(0, "GPIOA0"),
+               STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"),
+               STM32_FUNCTION(3, "TIM5_CH1"),
+               STM32_FUNCTION(4, "TIM8_ETR"),
+               STM32_FUNCTION(8, "USART2_CTS"),
+               STM32_FUNCTION(9, "UART4_TX"),
+               STM32_FUNCTION(11, "SAI2_SD_B"),
+               STM32_FUNCTION(12, "ETH_MII_CRS"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(1, "PA1"),
+               STM32_FUNCTION(0, "GPIOA1"),
+               STM32_FUNCTION(2, "TIM2_CH2"),
+               STM32_FUNCTION(3, "TIM5_CH2"),
+               STM32_FUNCTION(8, "USART2_RTS"),
+               STM32_FUNCTION(9, "UART4_RX"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO3"),
+               STM32_FUNCTION(11, "SAI2_MCLK_B"),
+               STM32_FUNCTION(12, "ETH_MII_RX_CLK ETH_RMII_REF_CLK"),
+               STM32_FUNCTION(15, "LCD_R2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(2, "PA2"),
+               STM32_FUNCTION(0, "GPIOA2"),
+               STM32_FUNCTION(2, "TIM2_CH3"),
+               STM32_FUNCTION(3, "TIM5_CH3"),
+               STM32_FUNCTION(4, "TIM9_CH1"),
+               STM32_FUNCTION(8, "USART2_TX"),
+               STM32_FUNCTION(9, "SAI2_SCK_B"),
+               STM32_FUNCTION(12, "ETH_MDIO"),
+               STM32_FUNCTION(15, "LCD_R1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(3, "PA3"),
+               STM32_FUNCTION(0, "GPIOA3"),
+               STM32_FUNCTION(2, "TIM2_CH4"),
+               STM32_FUNCTION(3, "TIM5_CH4"),
+               STM32_FUNCTION(4, "TIM9_CH2"),
+               STM32_FUNCTION(8, "USART2_RX"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D0"),
+               STM32_FUNCTION(12, "ETH_MII_COL"),
+               STM32_FUNCTION(15, "LCD_B5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(4, "PA4"),
+               STM32_FUNCTION(0, "GPIOA4"),
+               STM32_FUNCTION(6, "SPI1_NSS I2S1_WS"),
+               STM32_FUNCTION(7, "SPI3_NSS I2S3_WS"),
+               STM32_FUNCTION(8, "USART2_CK"),
+               STM32_FUNCTION(13, "OTG_HS_SOF"),
+               STM32_FUNCTION(14, "DCMI_HSYNC"),
+               STM32_FUNCTION(15, "LCD_VSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(5, "PA5"),
+               STM32_FUNCTION(0, "GPIOA5"),
+               STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"),
+               STM32_FUNCTION(4, "TIM8_CH1N"),
+               STM32_FUNCTION(6, "SPI1_SCK I2S1_CK"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_CK"),
+               STM32_FUNCTION(15, "LCD_R4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(6, "PA6"),
+               STM32_FUNCTION(0, "GPIOA6"),
+               STM32_FUNCTION(2, "TIM1_BKIN"),
+               STM32_FUNCTION(3, "TIM3_CH1"),
+               STM32_FUNCTION(4, "TIM8_BKIN"),
+               STM32_FUNCTION(6, "SPI1_MISO"),
+               STM32_FUNCTION(10, "TIM13_CH1"),
+               STM32_FUNCTION(14, "DCMI_PIXCLK"),
+               STM32_FUNCTION(15, "LCD_G2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(7, "PA7"),
+               STM32_FUNCTION(0, "GPIOA7"),
+               STM32_FUNCTION(2, "TIM1_CH1N"),
+               STM32_FUNCTION(3, "TIM3_CH2"),
+               STM32_FUNCTION(4, "TIM8_CH1N"),
+               STM32_FUNCTION(6, "SPI1_MOSI I2S1_SD"),
+               STM32_FUNCTION(10, "TIM14_CH1"),
+               STM32_FUNCTION(12, "ETH_MII_RX_DV ETH_RMII_CRS_DV"),
+               STM32_FUNCTION(13, "FMC_SDNWE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(8, "PA8"),
+               STM32_FUNCTION(0, "GPIOA8"),
+               STM32_FUNCTION(1, "MCO1"),
+               STM32_FUNCTION(2, "TIM1_CH1"),
+               STM32_FUNCTION(4, "TIM8_BKIN2"),
+               STM32_FUNCTION(5, "I2C3_SCL"),
+               STM32_FUNCTION(8, "USART1_CK"),
+               STM32_FUNCTION(11, "OTG_FS_SOF"),
+               STM32_FUNCTION(15, "LCD_R6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(9, "PA9"),
+               STM32_FUNCTION(0, "GPIOA9"),
+               STM32_FUNCTION(2, "TIM1_CH2"),
+               STM32_FUNCTION(5, "I2C3_SMBA"),
+               STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"),
+               STM32_FUNCTION(8, "USART1_TX"),
+               STM32_FUNCTION(14, "DCMI_D0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(10, "PA10"),
+               STM32_FUNCTION(0, "GPIOA10"),
+               STM32_FUNCTION(2, "TIM1_CH3"),
+               STM32_FUNCTION(8, "USART1_RX"),
+               STM32_FUNCTION(11, "OTG_FS_ID"),
+               STM32_FUNCTION(14, "DCMI_D1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(11, "PA11"),
+               STM32_FUNCTION(0, "GPIOA11"),
+               STM32_FUNCTION(2, "TIM1_CH4"),
+               STM32_FUNCTION(8, "USART1_CTS"),
+               STM32_FUNCTION(10, "CAN1_RX"),
+               STM32_FUNCTION(11, "OTG_FS_DM"),
+               STM32_FUNCTION(15, "LCD_R4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(12, "PA12"),
+               STM32_FUNCTION(0, "GPIOA12"),
+               STM32_FUNCTION(2, "TIM1_ETR"),
+               STM32_FUNCTION(8, "USART1_RTS"),
+               STM32_FUNCTION(9, "SAI2_FS_B"),
+               STM32_FUNCTION(10, "CAN1_TX"),
+               STM32_FUNCTION(11, "OTG_FS_DP"),
+               STM32_FUNCTION(15, "LCD_R5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(13, "PA13"),
+               STM32_FUNCTION(0, "GPIOA13"),
+               STM32_FUNCTION(1, "JTMS SWDIO"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(14, "PA14"),
+               STM32_FUNCTION(0, "GPIOA14"),
+               STM32_FUNCTION(1, "JTCK SWCLK"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(15, "PA15"),
+               STM32_FUNCTION(0, "GPIOA15"),
+               STM32_FUNCTION(1, "JTDI"),
+               STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"),
+               STM32_FUNCTION(5, "HDMI_CEC"),
+               STM32_FUNCTION(6, "SPI1_NSS I2S1_WS"),
+               STM32_FUNCTION(7, "SPI3_NSS I2S3_WS"),
+               STM32_FUNCTION(9, "UART4_RTS"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(16, "PB0"),
+               STM32_FUNCTION(0, "GPIOB0"),
+               STM32_FUNCTION(2, "TIM1_CH2N"),
+               STM32_FUNCTION(3, "TIM3_CH3"),
+               STM32_FUNCTION(4, "TIM8_CH2N"),
+               STM32_FUNCTION(9, "UART4_CTS"),
+               STM32_FUNCTION(10, "LCD_R3"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D1"),
+               STM32_FUNCTION(12, "ETH_MII_RXD2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(17, "PB1"),
+               STM32_FUNCTION(0, "GPIOB1"),
+               STM32_FUNCTION(2, "TIM1_CH3N"),
+               STM32_FUNCTION(3, "TIM3_CH4"),
+               STM32_FUNCTION(4, "TIM8_CH3N"),
+               STM32_FUNCTION(10, "LCD_R6"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D2"),
+               STM32_FUNCTION(12, "ETH_MII_RXD3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(18, "PB2"),
+               STM32_FUNCTION(0, "GPIOB2"),
+               STM32_FUNCTION(7, "SAI1_SD_A"),
+               STM32_FUNCTION(8, "SPI3_MOSI I2S3_SD"),
+               STM32_FUNCTION(10, "QUADSPI_CLK"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(19, "PB3"),
+               STM32_FUNCTION(0, "GPIOB3"),
+               STM32_FUNCTION(1, "JTDO TRACESWO"),
+               STM32_FUNCTION(2, "TIM2_CH2"),
+               STM32_FUNCTION(6, "SPI1_SCK I2S1_CK"),
+               STM32_FUNCTION(7, "SPI3_SCK I2S3_CK"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(20, "PB4"),
+               STM32_FUNCTION(0, "GPIOB4"),
+               STM32_FUNCTION(1, "NJTRST"),
+               STM32_FUNCTION(3, "TIM3_CH1"),
+               STM32_FUNCTION(6, "SPI1_MISO"),
+               STM32_FUNCTION(7, "SPI3_MISO"),
+               STM32_FUNCTION(8, "SPI2_NSS I2S2_WS"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(21, "PB5"),
+               STM32_FUNCTION(0, "GPIOB5"),
+               STM32_FUNCTION(3, "TIM3_CH2"),
+               STM32_FUNCTION(5, "I2C1_SMBA"),
+               STM32_FUNCTION(6, "SPI1_MOSI I2S1_SD"),
+               STM32_FUNCTION(7, "SPI3_MOSI I2S3_SD"),
+               STM32_FUNCTION(10, "CAN2_RX"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D7"),
+               STM32_FUNCTION(12, "ETH_PPS_OUT"),
+               STM32_FUNCTION(13, "FMC_SDCKE1"),
+               STM32_FUNCTION(14, "DCMI_D10"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(22, "PB6"),
+               STM32_FUNCTION(0, "GPIOB6"),
+               STM32_FUNCTION(3, "TIM4_CH1"),
+               STM32_FUNCTION(4, "HDMI_CEC"),
+               STM32_FUNCTION(5, "I2C1_SCL"),
+               STM32_FUNCTION(8, "USART1_TX"),
+               STM32_FUNCTION(10, "CAN2_TX"),
+               STM32_FUNCTION(11, "QUADSPI_BK1_NCS"),
+               STM32_FUNCTION(13, "FMC_SDNE1"),
+               STM32_FUNCTION(14, "DCMI_D5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(23, "PB7"),
+               STM32_FUNCTION(0, "GPIOB7"),
+               STM32_FUNCTION(3, "TIM4_CH2"),
+               STM32_FUNCTION(5, "I2C1_SDA"),
+               STM32_FUNCTION(8, "USART1_RX"),
+               STM32_FUNCTION(13, "FMC_NL"),
+               STM32_FUNCTION(14, "DCMI_VSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(24, "PB8"),
+               STM32_FUNCTION(0, "GPIOB8"),
+               STM32_FUNCTION(3, "TIM4_CH3"),
+               STM32_FUNCTION(4, "TIM10_CH1"),
+               STM32_FUNCTION(5, "I2C1_SCL"),
+               STM32_FUNCTION(10, "CAN1_RX"),
+               STM32_FUNCTION(12, "ETH_MII_TXD3"),
+               STM32_FUNCTION(13, "SDMMC1_D4"),
+               STM32_FUNCTION(14, "DCMI_D6"),
+               STM32_FUNCTION(15, "LCD_B6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(25, "PB9"),
+               STM32_FUNCTION(0, "GPIOB9"),
+               STM32_FUNCTION(3, "TIM4_CH4"),
+               STM32_FUNCTION(4, "TIM11_CH1"),
+               STM32_FUNCTION(5, "I2C1_SDA"),
+               STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"),
+               STM32_FUNCTION(10, "CAN1_TX"),
+               STM32_FUNCTION(13, "SDMMC1_D5"),
+               STM32_FUNCTION(14, "DCMI_D7"),
+               STM32_FUNCTION(15, "LCD_B7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(26, "PB10"),
+               STM32_FUNCTION(0, "GPIOB10"),
+               STM32_FUNCTION(2, "TIM2_CH3"),
+               STM32_FUNCTION(5, "I2C2_SCL"),
+               STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"),
+               STM32_FUNCTION(8, "USART3_TX"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D3"),
+               STM32_FUNCTION(12, "ETH_MII_RX_ER"),
+               STM32_FUNCTION(15, "LCD_G4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(27, "PB11"),
+               STM32_FUNCTION(0, "GPIOB11"),
+               STM32_FUNCTION(2, "TIM2_CH4"),
+               STM32_FUNCTION(5, "I2C2_SDA"),
+               STM32_FUNCTION(8, "USART3_RX"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D4"),
+               STM32_FUNCTION(12, "ETH_MII_TX_EN ETH_RMII_TX_EN"),
+               STM32_FUNCTION(15, "LCD_G5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(28, "PB12"),
+               STM32_FUNCTION(0, "GPIOB12"),
+               STM32_FUNCTION(2, "TIM1_BKIN"),
+               STM32_FUNCTION(5, "I2C2_SMBA"),
+               STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"),
+               STM32_FUNCTION(8, "USART3_CK"),
+               STM32_FUNCTION(10, "CAN2_RX"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D5"),
+               STM32_FUNCTION(12, "ETH_MII_TXD0 ETH_RMII_TXD0"),
+               STM32_FUNCTION(13, "OTG_HS_ID"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(29, "PB13"),
+               STM32_FUNCTION(0, "GPIOB13"),
+               STM32_FUNCTION(2, "TIM1_CH1N"),
+               STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"),
+               STM32_FUNCTION(8, "USART3_CTS"),
+               STM32_FUNCTION(10, "CAN2_TX"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D6"),
+               STM32_FUNCTION(12, "ETH_MII_TXD1 ETH_RMII_TXD1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(30, "PB14"),
+               STM32_FUNCTION(0, "GPIOB14"),
+               STM32_FUNCTION(2, "TIM1_CH2N"),
+               STM32_FUNCTION(4, "TIM8_CH2N"),
+               STM32_FUNCTION(6, "SPI2_MISO"),
+               STM32_FUNCTION(8, "USART3_RTS"),
+               STM32_FUNCTION(10, "TIM12_CH1"),
+               STM32_FUNCTION(13, "OTG_HS_DM"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(31, "PB15"),
+               STM32_FUNCTION(0, "GPIOB15"),
+               STM32_FUNCTION(1, "RTC_REFIN"),
+               STM32_FUNCTION(2, "TIM1_CH3N"),
+               STM32_FUNCTION(4, "TIM8_CH3N"),
+               STM32_FUNCTION(6, "SPI2_MOSI I2S2_SD"),
+               STM32_FUNCTION(10, "TIM12_CH2"),
+               STM32_FUNCTION(13, "OTG_HS_DP"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(32, "PC0"),
+               STM32_FUNCTION(0, "GPIOC0"),
+               STM32_FUNCTION(9, "SAI2_FS_B"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_STP"),
+               STM32_FUNCTION(13, "FMC_SDNWE"),
+               STM32_FUNCTION(15, "LCD_R5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(33, "PC1"),
+               STM32_FUNCTION(0, "GPIOC1"),
+               STM32_FUNCTION(1, "TRACED0"),
+               STM32_FUNCTION(6, "SPI2_MOSI I2S2_SD"),
+               STM32_FUNCTION(7, "SAI1_SD_A"),
+               STM32_FUNCTION(12, "ETH_MDC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(34, "PC2"),
+               STM32_FUNCTION(0, "GPIOC2"),
+               STM32_FUNCTION(6, "SPI2_MISO"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_DIR"),
+               STM32_FUNCTION(12, "ETH_MII_TXD2"),
+               STM32_FUNCTION(13, "FMC_SDNE0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(35, "PC3"),
+               STM32_FUNCTION(0, "GPIOC3"),
+               STM32_FUNCTION(6, "SPI2_MOSI I2S2_SD"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_NXT"),
+               STM32_FUNCTION(12, "ETH_MII_TX_CLK"),
+               STM32_FUNCTION(13, "FMC_SDCKE0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(36, "PC4"),
+               STM32_FUNCTION(0, "GPIOC4"),
+               STM32_FUNCTION(6, "I2S1_MCK"),
+               STM32_FUNCTION(9, "SPDIFRX_IN2"),
+               STM32_FUNCTION(12, "ETH_MII_RXD0 ETH_RMII_RXD0"),
+               STM32_FUNCTION(13, "FMC_SDNE0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(37, "PC5"),
+               STM32_FUNCTION(0, "GPIOC5"),
+               STM32_FUNCTION(9, "SPDIFRX_IN3"),
+               STM32_FUNCTION(12, "ETH_MII_RXD1 ETH_RMII_RXD1"),
+               STM32_FUNCTION(13, "FMC_SDCKE0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(38, "PC6"),
+               STM32_FUNCTION(0, "GPIOC6"),
+               STM32_FUNCTION(3, "TIM3_CH1"),
+               STM32_FUNCTION(4, "TIM8_CH1"),
+               STM32_FUNCTION(6, "I2S2_MCK"),
+               STM32_FUNCTION(9, "USART6_TX"),
+               STM32_FUNCTION(13, "SDMMC1_D6"),
+               STM32_FUNCTION(14, "DCMI_D0"),
+               STM32_FUNCTION(15, "LCD_HSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(39, "PC7"),
+               STM32_FUNCTION(0, "GPIOC7"),
+               STM32_FUNCTION(3, "TIM3_CH2"),
+               STM32_FUNCTION(4, "TIM8_CH2"),
+               STM32_FUNCTION(7, "I2S3_MCK"),
+               STM32_FUNCTION(9, "USART6_RX"),
+               STM32_FUNCTION(13, "SDMMC1_D7"),
+               STM32_FUNCTION(14, "DCMI_D1"),
+               STM32_FUNCTION(15, "LCD_G6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(40, "PC8"),
+               STM32_FUNCTION(0, "GPIOC8"),
+               STM32_FUNCTION(1, "TRACED1"),
+               STM32_FUNCTION(3, "TIM3_CH3"),
+               STM32_FUNCTION(4, "TIM8_CH3"),
+               STM32_FUNCTION(8, "UART5_RTS"),
+               STM32_FUNCTION(9, "USART6_CK"),
+               STM32_FUNCTION(13, "SDMMC1_D0"),
+               STM32_FUNCTION(14, "DCMI_D2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(41, "PC9"),
+               STM32_FUNCTION(0, "GPIOC9"),
+               STM32_FUNCTION(1, "MCO2"),
+               STM32_FUNCTION(3, "TIM3_CH4"),
+               STM32_FUNCTION(4, "TIM8_CH4"),
+               STM32_FUNCTION(5, "I2C3_SDA"),
+               STM32_FUNCTION(6, "I2S_CKIN"),
+               STM32_FUNCTION(8, "UART5_CTS"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO0"),
+               STM32_FUNCTION(13, "SDMMC1_D1"),
+               STM32_FUNCTION(14, "DCMI_D3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(42, "PC10"),
+               STM32_FUNCTION(0, "GPIOC10"),
+               STM32_FUNCTION(7, "SPI3_SCK I2S3_CK"),
+               STM32_FUNCTION(8, "USART3_TX"),
+               STM32_FUNCTION(9, "UART4_TX"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO1"),
+               STM32_FUNCTION(13, "SDMMC1_D2"),
+               STM32_FUNCTION(14, "DCMI_D8"),
+               STM32_FUNCTION(15, "LCD_R2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(43, "PC11"),
+               STM32_FUNCTION(0, "GPIOC11"),
+               STM32_FUNCTION(7, "SPI3_MISO"),
+               STM32_FUNCTION(8, "USART3_RX"),
+               STM32_FUNCTION(9, "UART4_RX"),
+               STM32_FUNCTION(10, "QUADSPI_BK2_NCS"),
+               STM32_FUNCTION(13, "SDMMC1_D3"),
+               STM32_FUNCTION(14, "DCMI_D4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(44, "PC12"),
+               STM32_FUNCTION(0, "GPIOC12"),
+               STM32_FUNCTION(1, "TRACED3"),
+               STM32_FUNCTION(7, "SPI3_MOSI I2S3_SD"),
+               STM32_FUNCTION(8, "USART3_CK"),
+               STM32_FUNCTION(9, "UART5_TX"),
+               STM32_FUNCTION(13, "SDMMC1_CK"),
+               STM32_FUNCTION(14, "DCMI_D9"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(45, "PC13"),
+               STM32_FUNCTION(0, "GPIOC13"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(46, "PC14"),
+               STM32_FUNCTION(0, "GPIOC14"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(47, "PC15"),
+               STM32_FUNCTION(0, "GPIOC15"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(48, "PD0"),
+               STM32_FUNCTION(0, "GPIOD0"),
+               STM32_FUNCTION(10, "CAN1_RX"),
+               STM32_FUNCTION(13, "FMC_D2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(49, "PD1"),
+               STM32_FUNCTION(0, "GPIOD1"),
+               STM32_FUNCTION(10, "CAN1_TX"),
+               STM32_FUNCTION(13, "FMC_D3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(50, "PD2"),
+               STM32_FUNCTION(0, "GPIOD2"),
+               STM32_FUNCTION(1, "TRACED2"),
+               STM32_FUNCTION(3, "TIM3_ETR"),
+               STM32_FUNCTION(9, "UART5_RX"),
+               STM32_FUNCTION(13, "SDMMC1_CMD"),
+               STM32_FUNCTION(14, "DCMI_D11"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(51, "PD3"),
+               STM32_FUNCTION(0, "GPIOD3"),
+               STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"),
+               STM32_FUNCTION(8, "USART2_CTS"),
+               STM32_FUNCTION(13, "FMC_CLK"),
+               STM32_FUNCTION(14, "DCMI_D5"),
+               STM32_FUNCTION(15, "LCD_G7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(52, "PD4"),
+               STM32_FUNCTION(0, "GPIOD4"),
+               STM32_FUNCTION(8, "USART2_RTS"),
+               STM32_FUNCTION(13, "FMC_NOE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(53, "PD5"),
+               STM32_FUNCTION(0, "GPIOD5"),
+               STM32_FUNCTION(8, "USART2_TX"),
+               STM32_FUNCTION(13, "FMC_NWE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(54, "PD6"),
+               STM32_FUNCTION(0, "GPIOD6"),
+               STM32_FUNCTION(6, "SPI3_MOSI I2S3_SD"),
+               STM32_FUNCTION(7, "SAI1_SD_A"),
+               STM32_FUNCTION(8, "USART2_RX"),
+               STM32_FUNCTION(13, "FMC_NWAIT"),
+               STM32_FUNCTION(14, "DCMI_D10"),
+               STM32_FUNCTION(15, "LCD_B2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(55, "PD7"),
+               STM32_FUNCTION(0, "GPIOD7"),
+               STM32_FUNCTION(8, "USART2_CK"),
+               STM32_FUNCTION(9, "SPDIFRX_IN0"),
+               STM32_FUNCTION(13, "FMC_NE1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(56, "PD8"),
+               STM32_FUNCTION(0, "GPIOD8"),
+               STM32_FUNCTION(8, "USART3_TX"),
+               STM32_FUNCTION(9, "SPDIFRX_IN1"),
+               STM32_FUNCTION(13, "FMC_D13"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(57, "PD9"),
+               STM32_FUNCTION(0, "GPIOD9"),
+               STM32_FUNCTION(8, "USART3_RX"),
+               STM32_FUNCTION(13, "FMC_D14"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(58, "PD10"),
+               STM32_FUNCTION(0, "GPIOD10"),
+               STM32_FUNCTION(8, "USART3_CK"),
+               STM32_FUNCTION(13, "FMC_D15"),
+               STM32_FUNCTION(15, "LCD_B3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(59, "PD11"),
+               STM32_FUNCTION(0, "GPIOD11"),
+               STM32_FUNCTION(5, "I2C4_SMBA"),
+               STM32_FUNCTION(8, "USART3_CTS"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO0"),
+               STM32_FUNCTION(11, "SAI2_SD_A"),
+               STM32_FUNCTION(13, "FMC_A16 FMC_CLE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(60, "PD12"),
+               STM32_FUNCTION(0, "GPIOD12"),
+               STM32_FUNCTION(3, "TIM4_CH1"),
+               STM32_FUNCTION(4, "LPTIM1_IN1"),
+               STM32_FUNCTION(5, "I2C4_SCL"),
+               STM32_FUNCTION(8, "USART3_RTS"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO1"),
+               STM32_FUNCTION(11, "SAI2_FS_A"),
+               STM32_FUNCTION(13, "FMC_A17 FMC_ALE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(61, "PD13"),
+               STM32_FUNCTION(0, "GPIOD13"),
+               STM32_FUNCTION(3, "TIM4_CH2"),
+               STM32_FUNCTION(4, "LPTIM1_OUT"),
+               STM32_FUNCTION(5, "I2C4_SDA"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO3"),
+               STM32_FUNCTION(11, "SAI2_SCK_A"),
+               STM32_FUNCTION(13, "FMC_A18"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(62, "PD14"),
+               STM32_FUNCTION(0, "GPIOD14"),
+               STM32_FUNCTION(3, "TIM4_CH3"),
+               STM32_FUNCTION(9, "UART8_CTS"),
+               STM32_FUNCTION(13, "FMC_D0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(63, "PD15"),
+               STM32_FUNCTION(0, "GPIOD15"),
+               STM32_FUNCTION(3, "TIM4_CH4"),
+               STM32_FUNCTION(9, "UART8_RTS"),
+               STM32_FUNCTION(13, "FMC_D1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(64, "PE0"),
+               STM32_FUNCTION(0, "GPIOE0"),
+               STM32_FUNCTION(3, "TIM4_ETR"),
+               STM32_FUNCTION(4, "LPTIM1_ETR"),
+               STM32_FUNCTION(9, "UART8_RX"),
+               STM32_FUNCTION(11, "SAI2_MCLK_A"),
+               STM32_FUNCTION(13, "FMC_NBL0"),
+               STM32_FUNCTION(14, "DCMI_D2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(65, "PE1"),
+               STM32_FUNCTION(0, "GPIOE1"),
+               STM32_FUNCTION(4, "LPTIM1_IN2"),
+               STM32_FUNCTION(9, "UART8_TX"),
+               STM32_FUNCTION(13, "FMC_NBL1"),
+               STM32_FUNCTION(14, "DCMI_D3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(66, "PE2"),
+               STM32_FUNCTION(0, "GPIOE2"),
+               STM32_FUNCTION(1, "TRACECLK"),
+               STM32_FUNCTION(6, "SPI4_SCK"),
+               STM32_FUNCTION(7, "SAI1_MCLK_A"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO2"),
+               STM32_FUNCTION(12, "ETH_MII_TXD3"),
+               STM32_FUNCTION(13, "FMC_A23"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(67, "PE3"),
+               STM32_FUNCTION(0, "GPIOE3"),
+               STM32_FUNCTION(1, "TRACED0"),
+               STM32_FUNCTION(7, "SAI1_SD_B"),
+               STM32_FUNCTION(13, "FMC_A19"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(68, "PE4"),
+               STM32_FUNCTION(0, "GPIOE4"),
+               STM32_FUNCTION(1, "TRACED1"),
+               STM32_FUNCTION(6, "SPI4_NSS"),
+               STM32_FUNCTION(7, "SAI1_FS_A"),
+               STM32_FUNCTION(13, "FMC_A20"),
+               STM32_FUNCTION(14, "DCMI_D4"),
+               STM32_FUNCTION(15, "LCD_B0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(69, "PE5"),
+               STM32_FUNCTION(0, "GPIOE5"),
+               STM32_FUNCTION(1, "TRACED2"),
+               STM32_FUNCTION(4, "TIM9_CH1"),
+               STM32_FUNCTION(6, "SPI4_MISO"),
+               STM32_FUNCTION(7, "SAI1_SCK_A"),
+               STM32_FUNCTION(13, "FMC_A21"),
+               STM32_FUNCTION(14, "DCMI_D6"),
+               STM32_FUNCTION(15, "LCD_G0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(70, "PE6"),
+               STM32_FUNCTION(0, "GPIOE6"),
+               STM32_FUNCTION(1, "TRACED3"),
+               STM32_FUNCTION(2, "TIM1_BKIN2"),
+               STM32_FUNCTION(4, "TIM9_CH2"),
+               STM32_FUNCTION(6, "SPI4_MOSI"),
+               STM32_FUNCTION(7, "SAI1_SD_A"),
+               STM32_FUNCTION(11, "SAI2_MCLK_B"),
+               STM32_FUNCTION(13, "FMC_A22"),
+               STM32_FUNCTION(14, "DCMI_D7"),
+               STM32_FUNCTION(15, "LCD_G1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(71, "PE7"),
+               STM32_FUNCTION(0, "GPIOE7"),
+               STM32_FUNCTION(2, "TIM1_ETR"),
+               STM32_FUNCTION(9, "UART7_RX"),
+               STM32_FUNCTION(11, "QUADSPI_BK2_IO0"),
+               STM32_FUNCTION(13, "FMC_D4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(72, "PE8"),
+               STM32_FUNCTION(0, "GPIOE8"),
+               STM32_FUNCTION(2, "TIM1_CH1N"),
+               STM32_FUNCTION(9, "UART7_TX"),
+               STM32_FUNCTION(11, "QUADSPI_BK2_IO1"),
+               STM32_FUNCTION(13, "FMC_D5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(73, "PE9"),
+               STM32_FUNCTION(0, "GPIOE9"),
+               STM32_FUNCTION(2, "TIM1_CH1"),
+               STM32_FUNCTION(9, "UART7_RTS"),
+               STM32_FUNCTION(11, "QUADSPI_BK2_IO2"),
+               STM32_FUNCTION(13, "FMC_D6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(74, "PE10"),
+               STM32_FUNCTION(0, "GPIOE10"),
+               STM32_FUNCTION(2, "TIM1_CH2N"),
+               STM32_FUNCTION(9, "UART7_CTS"),
+               STM32_FUNCTION(11, "QUADSPI_BK2_IO3"),
+               STM32_FUNCTION(13, "FMC_D7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(75, "PE11"),
+               STM32_FUNCTION(0, "GPIOE11"),
+               STM32_FUNCTION(2, "TIM1_CH2"),
+               STM32_FUNCTION(6, "SPI4_NSS"),
+               STM32_FUNCTION(11, "SAI2_SD_B"),
+               STM32_FUNCTION(13, "FMC_D8"),
+               STM32_FUNCTION(15, "LCD_G3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(76, "PE12"),
+               STM32_FUNCTION(0, "GPIOE12"),
+               STM32_FUNCTION(2, "TIM1_CH3N"),
+               STM32_FUNCTION(6, "SPI4_SCK"),
+               STM32_FUNCTION(11, "SAI2_SCK_B"),
+               STM32_FUNCTION(13, "FMC_D9"),
+               STM32_FUNCTION(15, "LCD_B4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(77, "PE13"),
+               STM32_FUNCTION(0, "GPIOE13"),
+               STM32_FUNCTION(2, "TIM1_CH3"),
+               STM32_FUNCTION(6, "SPI4_MISO"),
+               STM32_FUNCTION(11, "SAI2_FS_B"),
+               STM32_FUNCTION(13, "FMC_D10"),
+               STM32_FUNCTION(15, "LCD_DE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(78, "PE14"),
+               STM32_FUNCTION(0, "GPIOE14"),
+               STM32_FUNCTION(2, "TIM1_CH4"),
+               STM32_FUNCTION(6, "SPI4_MOSI"),
+               STM32_FUNCTION(11, "SAI2_MCLK_B"),
+               STM32_FUNCTION(13, "FMC_D11"),
+               STM32_FUNCTION(15, "LCD_CLK"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(79, "PE15"),
+               STM32_FUNCTION(0, "GPIOE15"),
+               STM32_FUNCTION(2, "TIM1_BKIN"),
+               STM32_FUNCTION(13, "FMC_D12"),
+               STM32_FUNCTION(15, "LCD_R7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(80, "PF0"),
+               STM32_FUNCTION(0, "GPIOF0"),
+               STM32_FUNCTION(5, "I2C2_SDA"),
+               STM32_FUNCTION(13, "FMC_A0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(81, "PF1"),
+               STM32_FUNCTION(0, "GPIOF1"),
+               STM32_FUNCTION(5, "I2C2_SCL"),
+               STM32_FUNCTION(13, "FMC_A1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(82, "PF2"),
+               STM32_FUNCTION(0, "GPIOF2"),
+               STM32_FUNCTION(5, "I2C2_SMBA"),
+               STM32_FUNCTION(13, "FMC_A2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(83, "PF3"),
+               STM32_FUNCTION(0, "GPIOF3"),
+               STM32_FUNCTION(13, "FMC_A3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(84, "PF4"),
+               STM32_FUNCTION(0, "GPIOF4"),
+               STM32_FUNCTION(13, "FMC_A4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(85, "PF5"),
+               STM32_FUNCTION(0, "GPIOF5"),
+               STM32_FUNCTION(13, "FMC_A5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(86, "PF6"),
+               STM32_FUNCTION(0, "GPIOF6"),
+               STM32_FUNCTION(4, "TIM10_CH1"),
+               STM32_FUNCTION(6, "SPI5_NSS"),
+               STM32_FUNCTION(7, "SAI1_SD_B"),
+               STM32_FUNCTION(9, "UART7_RX"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(87, "PF7"),
+               STM32_FUNCTION(0, "GPIOF7"),
+               STM32_FUNCTION(4, "TIM11_CH1"),
+               STM32_FUNCTION(6, "SPI5_SCK"),
+               STM32_FUNCTION(7, "SAI1_MCLK_B"),
+               STM32_FUNCTION(9, "UART7_TX"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(88, "PF8"),
+               STM32_FUNCTION(0, "GPIOF8"),
+               STM32_FUNCTION(6, "SPI5_MISO"),
+               STM32_FUNCTION(7, "SAI1_SCK_B"),
+               STM32_FUNCTION(9, "UART7_RTS"),
+               STM32_FUNCTION(10, "TIM13_CH1"),
+               STM32_FUNCTION(11, "QUADSPI_BK1_IO0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(89, "PF9"),
+               STM32_FUNCTION(0, "GPIOF9"),
+               STM32_FUNCTION(6, "SPI5_MOSI"),
+               STM32_FUNCTION(7, "SAI1_FS_B"),
+               STM32_FUNCTION(9, "UART7_CTS"),
+               STM32_FUNCTION(10, "TIM14_CH1"),
+               STM32_FUNCTION(11, "QUADSPI_BK1_IO1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(90, "PF10"),
+               STM32_FUNCTION(0, "GPIOF10"),
+               STM32_FUNCTION(14, "DCMI_D11"),
+               STM32_FUNCTION(15, "LCD_DE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(91, "PF11"),
+               STM32_FUNCTION(0, "GPIOF11"),
+               STM32_FUNCTION(6, "SPI5_MOSI"),
+               STM32_FUNCTION(11, "SAI2_SD_B"),
+               STM32_FUNCTION(13, "FMC_SDNRAS"),
+               STM32_FUNCTION(14, "DCMI_D12"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(92, "PF12"),
+               STM32_FUNCTION(0, "GPIOF12"),
+               STM32_FUNCTION(13, "FMC_A6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(93, "PF13"),
+               STM32_FUNCTION(0, "GPIOF13"),
+               STM32_FUNCTION(5, "I2C4_SMBA"),
+               STM32_FUNCTION(13, "FMC_A7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(94, "PF14"),
+               STM32_FUNCTION(0, "GPIOF14"),
+               STM32_FUNCTION(5, "I2C4_SCL"),
+               STM32_FUNCTION(13, "FMC_A8"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(95, "PF15"),
+               STM32_FUNCTION(0, "GPIOF15"),
+               STM32_FUNCTION(5, "I2C4_SDA"),
+               STM32_FUNCTION(13, "FMC_A9"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(96, "PG0"),
+               STM32_FUNCTION(0, "GPIOG0"),
+               STM32_FUNCTION(13, "FMC_A10"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(97, "PG1"),
+               STM32_FUNCTION(0, "GPIOG1"),
+               STM32_FUNCTION(13, "FMC_A11"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(98, "PG2"),
+               STM32_FUNCTION(0, "GPIOG2"),
+               STM32_FUNCTION(13, "FMC_A12"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(99, "PG3"),
+               STM32_FUNCTION(0, "GPIOG3"),
+               STM32_FUNCTION(13, "FMC_A13"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(100, "PG4"),
+               STM32_FUNCTION(0, "GPIOG4"),
+               STM32_FUNCTION(13, "FMC_A14 FMC_BA0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(101, "PG5"),
+               STM32_FUNCTION(0, "GPIOG5"),
+               STM32_FUNCTION(13, "FMC_A15 FMC_BA1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(102, "PG6"),
+               STM32_FUNCTION(0, "GPIOG6"),
+               STM32_FUNCTION(14, "DCMI_D12"),
+               STM32_FUNCTION(15, "LCD_R7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(103, "PG7"),
+               STM32_FUNCTION(0, "GPIOG7"),
+               STM32_FUNCTION(9, "USART6_CK"),
+               STM32_FUNCTION(13, "FMC_INT"),
+               STM32_FUNCTION(14, "DCMI_D13"),
+               STM32_FUNCTION(15, "LCD_CLK"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(104, "PG8"),
+               STM32_FUNCTION(0, "GPIOG8"),
+               STM32_FUNCTION(6, "SPI6_NSS"),
+               STM32_FUNCTION(8, "SPDIFRX_IN2"),
+               STM32_FUNCTION(9, "USART6_RTS"),
+               STM32_FUNCTION(12, "ETH_PPS_OUT"),
+               STM32_FUNCTION(13, "FMC_SDCLK"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(105, "PG9"),
+               STM32_FUNCTION(0, "GPIOG9"),
+               STM32_FUNCTION(8, "SPDIFRX_IN3"),
+               STM32_FUNCTION(9, "USART6_RX"),
+               STM32_FUNCTION(10, "QUADSPI_BK2_IO2"),
+               STM32_FUNCTION(11, "SAI2_FS_B"),
+               STM32_FUNCTION(13, "FMC_NE2 FMC_NCE"),
+               STM32_FUNCTION(14, "DCMI_VSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(106, "PG10"),
+               STM32_FUNCTION(0, "GPIOG10"),
+               STM32_FUNCTION(10, "LCD_G3"),
+               STM32_FUNCTION(11, "SAI2_SD_B"),
+               STM32_FUNCTION(13, "FMC_NE3"),
+               STM32_FUNCTION(14, "DCMI_D2"),
+               STM32_FUNCTION(15, "LCD_B2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(107, "PG11"),
+               STM32_FUNCTION(0, "GPIOG11"),
+               STM32_FUNCTION(8, "SPDIFRX_IN0"),
+               STM32_FUNCTION(12, "ETH_MII_TX_EN ETH_RMII_TX_EN"),
+               STM32_FUNCTION(14, "DCMI_D3"),
+               STM32_FUNCTION(15, "LCD_B3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(108, "PG12"),
+               STM32_FUNCTION(0, "GPIOG12"),
+               STM32_FUNCTION(4, "LPTIM1_IN1"),
+               STM32_FUNCTION(6, "SPI6_MISO"),
+               STM32_FUNCTION(8, "SPDIFRX_IN1"),
+               STM32_FUNCTION(9, "USART6_RTS"),
+               STM32_FUNCTION(10, "LCD_B4"),
+               STM32_FUNCTION(13, "FMC_NE4"),
+               STM32_FUNCTION(15, "LCD_B1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(109, "PG13"),
+               STM32_FUNCTION(0, "GPIOG13"),
+               STM32_FUNCTION(1, "TRACED0"),
+               STM32_FUNCTION(4, "LPTIM1_OUT"),
+               STM32_FUNCTION(6, "SPI6_SCK"),
+               STM32_FUNCTION(9, "USART6_CTS"),
+               STM32_FUNCTION(12, "ETH_MII_TXD0 ETH_RMII_TXD0"),
+               STM32_FUNCTION(13, "FMC_A24"),
+               STM32_FUNCTION(15, "LCD_R0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(110, "PG14"),
+               STM32_FUNCTION(0, "GPIOG14"),
+               STM32_FUNCTION(1, "TRACED1"),
+               STM32_FUNCTION(4, "LPTIM1_ETR"),
+               STM32_FUNCTION(6, "SPI6_MOSI"),
+               STM32_FUNCTION(9, "USART6_TX"),
+               STM32_FUNCTION(10, "QUADSPI_BK2_IO3"),
+               STM32_FUNCTION(12, "ETH_MII_TXD1 ETH_RMII_TXD1"),
+               STM32_FUNCTION(13, "FMC_A25"),
+               STM32_FUNCTION(15, "LCD_B0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(111, "PG15"),
+               STM32_FUNCTION(0, "GPIOG15"),
+               STM32_FUNCTION(9, "USART6_CTS"),
+               STM32_FUNCTION(13, "FMC_SDNCAS"),
+               STM32_FUNCTION(14, "DCMI_D13"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(112, "PH0"),
+               STM32_FUNCTION(0, "GPIOH0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(113, "PH1"),
+               STM32_FUNCTION(0, "GPIOH1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(114, "PH2"),
+               STM32_FUNCTION(0, "GPIOH2"),
+               STM32_FUNCTION(4, "LPTIM1_IN2"),
+               STM32_FUNCTION(10, "QUADSPI_BK2_IO0"),
+               STM32_FUNCTION(11, "SAI2_SCK_B"),
+               STM32_FUNCTION(12, "ETH_MII_CRS"),
+               STM32_FUNCTION(13, "FMC_SDCKE0"),
+               STM32_FUNCTION(15, "LCD_R0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(115, "PH3"),
+               STM32_FUNCTION(0, "GPIOH3"),
+               STM32_FUNCTION(10, "QUADSPI_BK2_IO1"),
+               STM32_FUNCTION(11, "SAI2_MCLK_B"),
+               STM32_FUNCTION(12, "ETH_MII_COL"),
+               STM32_FUNCTION(13, "FMC_SDNE0"),
+               STM32_FUNCTION(15, "LCD_R1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(116, "PH4"),
+               STM32_FUNCTION(0, "GPIOH4"),
+               STM32_FUNCTION(5, "I2C2_SCL"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_NXT"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(117, "PH5"),
+               STM32_FUNCTION(0, "GPIOH5"),
+               STM32_FUNCTION(5, "I2C2_SDA"),
+               STM32_FUNCTION(6, "SPI5_NSS"),
+               STM32_FUNCTION(13, "FMC_SDNWE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(118, "PH6"),
+               STM32_FUNCTION(0, "GPIOH6"),
+               STM32_FUNCTION(5, "I2C2_SMBA"),
+               STM32_FUNCTION(6, "SPI5_SCK"),
+               STM32_FUNCTION(10, "TIM12_CH1"),
+               STM32_FUNCTION(12, "ETH_MII_RXD2"),
+               STM32_FUNCTION(13, "FMC_SDNE1"),
+               STM32_FUNCTION(14, "DCMI_D8"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(119, "PH7"),
+               STM32_FUNCTION(0, "GPIOH7"),
+               STM32_FUNCTION(5, "I2C3_SCL"),
+               STM32_FUNCTION(6, "SPI5_MISO"),
+               STM32_FUNCTION(12, "ETH_MII_RXD3"),
+               STM32_FUNCTION(13, "FMC_SDCKE1"),
+               STM32_FUNCTION(14, "DCMI_D9"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(120, "PH8"),
+               STM32_FUNCTION(0, "GPIOH8"),
+               STM32_FUNCTION(5, "I2C3_SDA"),
+               STM32_FUNCTION(13, "FMC_D16"),
+               STM32_FUNCTION(14, "DCMI_HSYNC"),
+               STM32_FUNCTION(15, "LCD_R2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(121, "PH9"),
+               STM32_FUNCTION(0, "GPIOH9"),
+               STM32_FUNCTION(5, "I2C3_SMBA"),
+               STM32_FUNCTION(10, "TIM12_CH2"),
+               STM32_FUNCTION(13, "FMC_D17"),
+               STM32_FUNCTION(14, "DCMI_D0"),
+               STM32_FUNCTION(15, "LCD_R3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(122, "PH10"),
+               STM32_FUNCTION(0, "GPIOH10"),
+               STM32_FUNCTION(3, "TIM5_CH1"),
+               STM32_FUNCTION(5, "I2C4_SMBA"),
+               STM32_FUNCTION(13, "FMC_D18"),
+               STM32_FUNCTION(14, "DCMI_D1"),
+               STM32_FUNCTION(15, "LCD_R4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(123, "PH11"),
+               STM32_FUNCTION(0, "GPIOH11"),
+               STM32_FUNCTION(3, "TIM5_CH2"),
+               STM32_FUNCTION(5, "I2C4_SCL"),
+               STM32_FUNCTION(13, "FMC_D19"),
+               STM32_FUNCTION(14, "DCMI_D2"),
+               STM32_FUNCTION(15, "LCD_R5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(124, "PH12"),
+               STM32_FUNCTION(0, "GPIOH12"),
+               STM32_FUNCTION(3, "TIM5_CH3"),
+               STM32_FUNCTION(5, "I2C4_SDA"),
+               STM32_FUNCTION(13, "FMC_D20"),
+               STM32_FUNCTION(14, "DCMI_D3"),
+               STM32_FUNCTION(15, "LCD_R6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(125, "PH13"),
+               STM32_FUNCTION(0, "GPIOH13"),
+               STM32_FUNCTION(4, "TIM8_CH1N"),
+               STM32_FUNCTION(10, "CAN1_TX"),
+               STM32_FUNCTION(13, "FMC_D21"),
+               STM32_FUNCTION(15, "LCD_G2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(126, "PH14"),
+               STM32_FUNCTION(0, "GPIOH14"),
+               STM32_FUNCTION(4, "TIM8_CH2N"),
+               STM32_FUNCTION(13, "FMC_D22"),
+               STM32_FUNCTION(14, "DCMI_D4"),
+               STM32_FUNCTION(15, "LCD_G3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(127, "PH15"),
+               STM32_FUNCTION(0, "GPIOH15"),
+               STM32_FUNCTION(4, "TIM8_CH3N"),
+               STM32_FUNCTION(13, "FMC_D23"),
+               STM32_FUNCTION(14, "DCMI_D11"),
+               STM32_FUNCTION(15, "LCD_G4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(128, "PI0"),
+               STM32_FUNCTION(0, "GPIOI0"),
+               STM32_FUNCTION(3, "TIM5_CH4"),
+               STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"),
+               STM32_FUNCTION(13, "FMC_D24"),
+               STM32_FUNCTION(14, "DCMI_D13"),
+               STM32_FUNCTION(15, "LCD_G5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(129, "PI1"),
+               STM32_FUNCTION(0, "GPIOI1"),
+               STM32_FUNCTION(4, "TIM8_BKIN2"),
+               STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"),
+               STM32_FUNCTION(13, "FMC_D25"),
+               STM32_FUNCTION(14, "DCMI_D8"),
+               STM32_FUNCTION(15, "LCD_G6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(130, "PI2"),
+               STM32_FUNCTION(0, "GPIOI2"),
+               STM32_FUNCTION(4, "TIM8_CH4"),
+               STM32_FUNCTION(6, "SPI2_MISO"),
+               STM32_FUNCTION(13, "FMC_D26"),
+               STM32_FUNCTION(14, "DCMI_D9"),
+               STM32_FUNCTION(15, "LCD_G7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(131, "PI3"),
+               STM32_FUNCTION(0, "GPIOI3"),
+               STM32_FUNCTION(4, "TIM8_ETR"),
+               STM32_FUNCTION(6, "SPI2_MOSI I2S2_SD"),
+               STM32_FUNCTION(13, "FMC_D27"),
+               STM32_FUNCTION(14, "DCMI_D10"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(132, "PI4"),
+               STM32_FUNCTION(0, "GPIOI4"),
+               STM32_FUNCTION(4, "TIM8_BKIN"),
+               STM32_FUNCTION(11, "SAI2_MCLK_A"),
+               STM32_FUNCTION(13, "FMC_NBL2"),
+               STM32_FUNCTION(14, "DCMI_D5"),
+               STM32_FUNCTION(15, "LCD_B4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(133, "PI5"),
+               STM32_FUNCTION(0, "GPIOI5"),
+               STM32_FUNCTION(4, "TIM8_CH1"),
+               STM32_FUNCTION(11, "SAI2_SCK_A"),
+               STM32_FUNCTION(13, "FMC_NBL3"),
+               STM32_FUNCTION(14, "DCMI_VSYNC"),
+               STM32_FUNCTION(15, "LCD_B5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(134, "PI6"),
+               STM32_FUNCTION(0, "GPIOI6"),
+               STM32_FUNCTION(4, "TIM8_CH2"),
+               STM32_FUNCTION(11, "SAI2_SD_A"),
+               STM32_FUNCTION(13, "FMC_D28"),
+               STM32_FUNCTION(14, "DCMI_D6"),
+               STM32_FUNCTION(15, "LCD_B6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(135, "PI7"),
+               STM32_FUNCTION(0, "GPIOI7"),
+               STM32_FUNCTION(4, "TIM8_CH3"),
+               STM32_FUNCTION(11, "SAI2_FS_A"),
+               STM32_FUNCTION(13, "FMC_D29"),
+               STM32_FUNCTION(14, "DCMI_D7"),
+               STM32_FUNCTION(15, "LCD_B7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(136, "PI8"),
+               STM32_FUNCTION(0, "GPIOI8"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(137, "PI9"),
+               STM32_FUNCTION(0, "GPIOI9"),
+               STM32_FUNCTION(10, "CAN1_RX"),
+               STM32_FUNCTION(13, "FMC_D30"),
+               STM32_FUNCTION(15, "LCD_VSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(138, "PI10"),
+               STM32_FUNCTION(0, "GPIOI10"),
+               STM32_FUNCTION(12, "ETH_MII_RX_ER"),
+               STM32_FUNCTION(13, "FMC_D31"),
+               STM32_FUNCTION(15, "LCD_HSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(139, "PI11"),
+               STM32_FUNCTION(0, "GPIOI11"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_DIR"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(140, "PI12"),
+               STM32_FUNCTION(0, "GPIOI12"),
+               STM32_FUNCTION(15, "LCD_HSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(141, "PI13"),
+               STM32_FUNCTION(0, "GPIOI13"),
+               STM32_FUNCTION(15, "LCD_VSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(142, "PI14"),
+               STM32_FUNCTION(0, "GPIOI14"),
+               STM32_FUNCTION(15, "LCD_CLK"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(143, "PI15"),
+               STM32_FUNCTION(0, "GPIOI15"),
+               STM32_FUNCTION(15, "LCD_R0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(144, "PJ0"),
+               STM32_FUNCTION(0, "GPIOJ0"),
+               STM32_FUNCTION(15, "LCD_R1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(145, "PJ1"),
+               STM32_FUNCTION(0, "GPIOJ1"),
+               STM32_FUNCTION(15, "LCD_R2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(146, "PJ2"),
+               STM32_FUNCTION(0, "GPIOJ2"),
+               STM32_FUNCTION(15, "LCD_R3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(147, "PJ3"),
+               STM32_FUNCTION(0, "GPIOJ3"),
+               STM32_FUNCTION(15, "LCD_R4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(148, "PJ4"),
+               STM32_FUNCTION(0, "GPIOJ4"),
+               STM32_FUNCTION(15, "LCD_R5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(149, "PJ5"),
+               STM32_FUNCTION(0, "GPIOJ5"),
+               STM32_FUNCTION(15, "LCD_R6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(150, "PJ6"),
+               STM32_FUNCTION(0, "GPIOJ6"),
+               STM32_FUNCTION(15, "LCD_R7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(151, "PJ7"),
+               STM32_FUNCTION(0, "GPIOJ7"),
+               STM32_FUNCTION(15, "LCD_G0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(152, "PJ8"),
+               STM32_FUNCTION(0, "GPIOJ8"),
+               STM32_FUNCTION(15, "LCD_G1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(153, "PJ9"),
+               STM32_FUNCTION(0, "GPIOJ9"),
+               STM32_FUNCTION(15, "LCD_G2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(154, "PJ10"),
+               STM32_FUNCTION(0, "GPIOJ10"),
+               STM32_FUNCTION(15, "LCD_G3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(155, "PJ11"),
+               STM32_FUNCTION(0, "GPIOJ11"),
+               STM32_FUNCTION(15, "LCD_G4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(156, "PJ12"),
+               STM32_FUNCTION(0, "GPIOJ12"),
+               STM32_FUNCTION(15, "LCD_B0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(157, "PJ13"),
+               STM32_FUNCTION(0, "GPIOJ13"),
+               STM32_FUNCTION(15, "LCD_B1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(158, "PJ14"),
+               STM32_FUNCTION(0, "GPIOJ14"),
+               STM32_FUNCTION(15, "LCD_B2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(159, "PJ15"),
+               STM32_FUNCTION(0, "GPIOJ15"),
+               STM32_FUNCTION(15, "LCD_B3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(160, "PK0"),
+               STM32_FUNCTION(0, "GPIOK0"),
+               STM32_FUNCTION(15, "LCD_G5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(161, "PK1"),
+               STM32_FUNCTION(0, "GPIOK1"),
+               STM32_FUNCTION(15, "LCD_G6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(162, "PK2"),
+               STM32_FUNCTION(0, "GPIOK2"),
+               STM32_FUNCTION(15, "LCD_G7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(163, "PK3"),
+               STM32_FUNCTION(0, "GPIOK3"),
+               STM32_FUNCTION(15, "LCD_B4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(164, "PK4"),
+               STM32_FUNCTION(0, "GPIOK4"),
+               STM32_FUNCTION(15, "LCD_B5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(165, "PK5"),
+               STM32_FUNCTION(0, "GPIOK5"),
+               STM32_FUNCTION(15, "LCD_B6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(166, "PK6"),
+               STM32_FUNCTION(0, "GPIOK6"),
+               STM32_FUNCTION(15, "LCD_B7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(167, "PK7"),
+               STM32_FUNCTION(0, "GPIOK7"),
+               STM32_FUNCTION(15, "LCD_DE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+};
+
+static struct stm32_pinctrl_match_data stm32f746_match_data = {
+       .pins = stm32f746_pins,
+       .npins = ARRAY_SIZE(stm32f746_pins),
+};
+
+static const struct of_device_id stm32f746_pctrl_match[] = {
+       {
+               .compatible = "st,stm32f746-pinctrl",
+               .data = &stm32f746_match_data,
+       },
+       { }
+};
+
+static struct platform_driver stm32f746_pinctrl_driver = {
+       .probe = stm32_pctl_probe,
+       .driver = {
+               .name = "stm32f746-pinctrl",
+               .of_match_table = stm32f746_pctrl_match,
+       },
+};
+builtin_platform_driver(stm32f746_pinctrl_driver);
index 55083d2..ce483b0 100644 (file)
@@ -180,17 +180,17 @@ static const struct sunxi_desc_pin sun8i_a23_pins[] = {
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQ6 */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ6 */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* D6 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQ7 */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ7 */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* D7 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQS */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQS */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* RST */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 17),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
index 8b381d6..3040abe 100644 (file)
@@ -140,17 +140,17 @@ static const struct sunxi_desc_pin sun8i_a33_pins[] = {
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQ6 */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ6 */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* D6 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQ7 */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ7 */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* D7 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQS */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQS */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* RST */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
index 11760bb..26a2ad3 100644 (file)
@@ -219,17 +219,17 @@ static const struct sunxi_desc_pin sun8i_h3_pins[] = {
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQ6 */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ6 */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* D6 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQ7 */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ7 */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* D7 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQS */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQS */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* RST */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 0),
index 6e82b29..277622b 100644 (file)
@@ -632,11 +632,11 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
        u32 val;
 
        for (i = 0; i < pmx->soc->ngroups; ++i) {
-               if (pmx->soc->groups[i].parked_reg >= 0) {
-                       g = &pmx->soc->groups[i];
-                       val = pmx_readl(pmx, g->parked_bank, g->parked_reg);
+               g = &pmx->soc->groups[i];
+               if (g->parked_bit >= 0) {
+                       val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
                        val &= ~(1 << g->parked_bit);
-                       pmx_writel(pmx, val, g->parked_bank, g->parked_reg);
+                       pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
                }
        }
 }
index d2ced17..33b17cb 100644 (file)
@@ -93,9 +93,7 @@ struct tegra_function {
  * @tri_reg:           Tri-state register offset.
  * @tri_bank:          Tri-state register bank.
  * @tri_bit:           Tri-state register bit.
- * @parked_reg:                Parked register offset. -1 if unsupported.
- * @parked_bank:       Parked register bank. 0 if unsupported.
- * @parked_bit:                Parked register bit. 0 if unsupported.
+ * @parked_bit:                Parked register bit. -1 if unsupported.
  * @einput_bit:                Enable-input register bit.
  * @odrain_bit:                Open-drain register bit.
  * @lock_bit:          Lock register bit.
@@ -138,12 +136,10 @@ struct tegra_pingroup {
        s16 pupd_reg;
        s16 tri_reg;
        s16 drv_reg;
-       s16 parked_reg;
        u32 mux_bank:2;
        u32 pupd_bank:2;
        u32 tri_bank:2;
        u32 drv_bank:2;
-       u32 parked_bank:2;
        s32 mux_bit:6;
        s32 pupd_bit:6;
        s32 tri_bit:6;
index 4851d16..952132c 100644 (file)
@@ -1578,7 +1578,7 @@ static struct tegra_function tegra114_functions[] = {
                .lock_bit = 7,                                          \
                .ioreset_bit = PINGROUP_BIT_##ior(8),                   \
                .rcv_sel_bit = PINGROUP_BIT_##rcv_sel(9),               \
-               .parked_reg = -1,                                       \
+               .parked_bit = -1,                                       \
                .drv_reg = -1,                                          \
        }
 
@@ -1599,7 +1599,7 @@ static struct tegra_function tegra114_functions[] = {
                .rcv_sel_bit = -1,                                      \
                .drv_reg = DRV_PINGROUP_REG(r),                         \
                .drv_bank = 0,                                          \
-               .parked_reg = -1,                                       \
+               .parked_bit = -1,                                       \
                .hsm_bit = hsm_b,                                       \
                .schmitt_bit = schmitt_b,                               \
                .lpmd_bit = lpmd_b,                                     \
index a0ce723..bca239e 100644 (file)
@@ -1747,7 +1747,7 @@ static struct tegra_function tegra124_functions[] = {
                .lock_bit = 7,                                          \
                .ioreset_bit = PINGROUP_BIT_##ior(8),                   \
                .rcv_sel_bit = PINGROUP_BIT_##rcv_sel(9),               \
-               .parked_reg = -1,                                       \
+               .parked_bit = -1,                                       \
                .drv_reg = -1,                                          \
        }
 
@@ -1768,7 +1768,7 @@ static struct tegra_function tegra124_functions[] = {
                .rcv_sel_bit = -1,                                      \
                .drv_reg = DRV_PINGROUP_REG(r),                         \
                .drv_bank = 0,                                          \
-               .parked_reg = -1,                                       \
+               .parked_bit = -1,                                       \
                .hsm_bit = hsm_b,                                       \
                .schmitt_bit = schmitt_b,                               \
                .lpmd_bit = lpmd_b,                                     \
index 09bad69..ad62451 100644 (file)
@@ -1994,7 +1994,7 @@ static struct tegra_function tegra20_functions[] = {
                .tri_reg = ((tri_r) - TRISTATE_REG_A),          \
                .tri_bank = 0,                                  \
                .tri_bit = tri_b,                               \
-               .parked_reg = -1,                               \
+               .parked_bit = -1,                               \
                .einput_bit = -1,                               \
                .odrain_bit = -1,                               \
                .lock_bit = -1,                                 \
@@ -2014,7 +2014,7 @@ static struct tegra_function tegra20_functions[] = {
                .pupd_bank = 2,                                 \
                .pupd_bit = pupd_b,                             \
                .drv_reg = -1,                                  \
-               .parked_reg = -1,                               \
+               .parked_bit = -1,                               \
        }
 
 /* Pin groups for drive strength registers (configurable version) */
@@ -2030,7 +2030,7 @@ static struct tegra_function tegra20_functions[] = {
                .tri_reg = -1,                                  \
                .drv_reg = ((r) - PINGROUP_REG_A),              \
                .drv_bank = 3,                                  \
-               .parked_reg = -1,                               \
+               .parked_bit = -1,                               \
                .hsm_bit = hsm_b,                               \
                .schmitt_bit = schmitt_b,                       \
                .lpmd_bit = lpmd_b,                             \
index 2d856af..2b70e93 100644 (file)
@@ -1310,8 +1310,6 @@ static struct tegra_function tegra210_functions[] = {
                .lock_bit = 7,                                          \
                .ioreset_bit = -1,                                      \
                .rcv_sel_bit = PINGROUP_BIT_##e_io_hv(10),              \
-               .parked_reg = PINGROUP_REG(r),                          \
-               .parked_bank = 1,                                       \
                .parked_bit = 5,                                        \
                .hsm_bit = PINGROUP_BIT_##hsm(9),                       \
                .schmitt_bit = 12,                                      \
@@ -1345,7 +1343,7 @@ static struct tegra_function tegra210_functions[] = {
                .rcv_sel_bit = -1,                                      \
                .drv_reg = DRV_PINGROUP_REG(r),                         \
                .drv_bank = 0,                                          \
-               .parked_reg = -1,                                       \
+               .parked_bit = -1,                                       \
                .hsm_bit = -1,                                          \
                .schmitt_bit = -1,                                      \
                .lpmd_bit = -1,                                         \
index fb7817f..474ac6d 100644 (file)
@@ -2139,7 +2139,7 @@ static struct tegra_function tegra30_functions[] = {
                .lock_bit = 7,                                          \
                .ioreset_bit = PINGROUP_BIT_##ior(8),                   \
                .rcv_sel_bit = -1,                                      \
-               .parked_reg = -1,                                       \
+               .parked_bit = -1,                                       \
                .drv_reg = -1,                                          \
        }
 
@@ -2160,7 +2160,7 @@ static struct tegra_function tegra30_functions[] = {
                .rcv_sel_bit = -1,                                      \
                .drv_reg = DRV_PINGROUP_REG(r),                         \
                .drv_bank = 0,                                          \
-               .parked_reg = -1,                                       \
+               .parked_bit = -1,                                       \
                .hsm_bit = hsm_b,                                       \
                .schmitt_bit = schmitt_b,                               \
                .lpmd_bit = lpmd_b,                                     \
index 0b40ded..e077a9e 100644 (file)
@@ -10,26 +10,34 @@ if PINCTRL_UNIPHIER
 
 config PINCTRL_UNIPHIER_LD4
        tristate "UniPhier PH1-LD4 SoC pinctrl driver"
-       default y
+       default ARM
 
 config PINCTRL_UNIPHIER_PRO4
        tristate "UniPhier PH1-Pro4 SoC pinctrl driver"
-       default y
+       default ARM
 
 config PINCTRL_UNIPHIER_SLD8
        tristate "UniPhier PH1-sLD8 SoC pinctrl driver"
-       default y
+       default ARM
 
 config PINCTRL_UNIPHIER_PRO5
        tristate "UniPhier PH1-Pro5 SoC pinctrl driver"
-       default y
+       default ARM
 
 config PINCTRL_UNIPHIER_PXS2
        tristate "UniPhier ProXstream2 SoC pinctrl driver"
-       default y
+       default ARM
 
 config PINCTRL_UNIPHIER_LD6B
        tristate "UniPhier PH1-LD6b SoC pinctrl driver"
-       default y
+       default ARM
+
+config PINCTRL_UNIPHIER_LD11
+       tristate "UniPhier PH1-LD11 SoC pinctrl driver"
+       default ARM64
+
+config PINCTRL_UNIPHIER_LD20
+       tristate "UniPhier PH1-LD20 SoC pinctrl driver"
+       default ARM64
 
 endif
index 3b8f9ee..9f4bc8a 100644 (file)
@@ -6,3 +6,5 @@ obj-$(CONFIG_PINCTRL_UNIPHIER_SLD8)     += pinctrl-uniphier-sld8.o
 obj-$(CONFIG_PINCTRL_UNIPHIER_PRO5)    += pinctrl-uniphier-pro5.o
 obj-$(CONFIG_PINCTRL_UNIPHIER_PXS2)    += pinctrl-uniphier-pxs2.o
 obj-$(CONFIG_PINCTRL_UNIPHIER_LD6B)    += pinctrl-uniphier-ld6b.o
+obj-$(CONFIG_PINCTRL_UNIPHIER_LD11)    += pinctrl-uniphier-ld11.o
+obj-$(CONFIG_PINCTRL_UNIPHIER_LD20)    += pinctrl-uniphier-ld20.o
index 9674009..9b2ee71 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/export.h>
 #include <linux/mfd/syscon.h>
+#include <linux/of.h>
 #include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinconf-generic.h>
 #include <linux/pinctrl/pinctrl.h>
 #include "pinctrl-uniphier.h"
 
 struct uniphier_pinctrl_priv {
+       struct pinctrl_desc pctldesc;
        struct pinctrl_dev *pctldev;
        struct regmap *regmap;
+       unsigned int regbase;
        struct uniphier_pinctrl_socdata *socdata;
 };
 
@@ -63,16 +66,22 @@ static int uniphier_pctl_get_group_pins(struct pinctrl_dev *pctldev,
 static void uniphier_pctl_pin_dbg_show(struct pinctrl_dev *pctldev,
                                       struct seq_file *s, unsigned offset)
 {
-       const struct pinctrl_pin_desc *pin = &pctldev->desc->pins[offset];
-       const char *pull_dir, *drv_str;
+       const struct pin_desc *desc = pin_desc_get(pctldev, offset);
+       const char *pull_dir, *drv_type;
 
-       switch (uniphier_pin_get_pull_dir(pin->drv_data)) {
+       switch (uniphier_pin_get_pull_dir(desc->drv_data)) {
        case UNIPHIER_PIN_PULL_UP:
                pull_dir = "UP";
                break;
        case UNIPHIER_PIN_PULL_DOWN:
                pull_dir = "DOWN";
                break;
+       case UNIPHIER_PIN_PULL_UP_FIXED:
+               pull_dir = "UP(FIXED)";
+               break;
+       case UNIPHIER_PIN_PULL_DOWN_FIXED:
+               pull_dir = "DOWN(FIXED)";
+               break;
        case UNIPHIER_PIN_PULL_NONE:
                pull_dir = "NONE";
                break;
@@ -80,30 +89,33 @@ static void uniphier_pctl_pin_dbg_show(struct pinctrl_dev *pctldev,
                BUG();
        }
 
-       switch (uniphier_pin_get_drv_str(pin->drv_data)) {
-       case UNIPHIER_PIN_DRV_4_8:
-               drv_str = "4/8(mA)";
+       switch (uniphier_pin_get_drv_type(desc->drv_data)) {
+       case UNIPHIER_PIN_DRV_1BIT:
+               drv_type = "4/8(mA)";
+               break;
+       case UNIPHIER_PIN_DRV_2BIT:
+               drv_type = "8/12/16/20(mA)";
                break;
-       case UNIPHIER_PIN_DRV_8_12_16_20:
-               drv_str = "8/12/16/20(mA)";
+       case UNIPHIER_PIN_DRV_3BIT:
+               drv_type = "4/5/7/9/11/12/14/16(mA)";
                break;
-       case UNIPHIER_PIN_DRV_FIXED_4:
-               drv_str = "4(mA)";
+       case UNIPHIER_PIN_DRV_FIXED4:
+               drv_type = "4(mA)";
                break;
-       case UNIPHIER_PIN_DRV_FIXED_5:
-               drv_str = "5(mA)";
+       case UNIPHIER_PIN_DRV_FIXED5:
+               drv_type = "5(mA)";
                break;
-       case UNIPHIER_PIN_DRV_FIXED_8:
-               drv_str = "8(mA)";
+       case UNIPHIER_PIN_DRV_FIXED8:
+               drv_type = "8(mA)";
                break;
        case UNIPHIER_PIN_DRV_NONE:
-               drv_str = "NONE";
+               drv_type = "NONE";
                break;
        default:
                BUG();
        }
 
-       seq_printf(s, " PULL_DIR=%s  DRV_STR=%s", pull_dir, drv_str);
+       seq_printf(s, " PULL_DIR=%s  DRV_TYPE=%s", pull_dir, drv_type);
 }
 #endif
 
@@ -119,12 +131,12 @@ static const struct pinctrl_ops uniphier_pctlops = {
 };
 
 static int uniphier_conf_pin_bias_get(struct pinctrl_dev *pctldev,
-                                     const struct pinctrl_pin_desc *pin,
+                                     const struct pin_desc *desc,
                                      enum pin_config_param param)
 {
        struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
        enum uniphier_pin_pull_dir pull_dir =
-                               uniphier_pin_get_pull_dir(pin->drv_data);
+                               uniphier_pin_get_pull_dir(desc->drv_data);
        unsigned int pupdctrl, reg, shift, val;
        unsigned int expected = 1;
        int ret;
@@ -154,12 +166,12 @@ static int uniphier_conf_pin_bias_get(struct pinctrl_dev *pctldev,
                BUG();
        }
 
-       pupdctrl = uniphier_pin_get_pupdctrl(pin->drv_data);
+       pupdctrl = uniphier_pin_get_pupdctrl(desc->drv_data);
 
        reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pupdctrl / 32 * 4;
        shift = pupdctrl % 32;
 
-       ret = regmap_read(priv->regmap, reg, &val);
+       ret = regmap_read(priv->regmap, priv->regbase + reg, &val);
        if (ret)
                return ret;
 
@@ -169,34 +181,42 @@ static int uniphier_conf_pin_bias_get(struct pinctrl_dev *pctldev,
 }
 
 static int uniphier_conf_pin_drive_get(struct pinctrl_dev *pctldev,
-                                      const struct pinctrl_pin_desc *pin,
+                                      const struct pin_desc *desc,
                                       u16 *strength)
 {
        struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
-       enum uniphier_pin_drv_str drv_str =
-                               uniphier_pin_get_drv_str(pin->drv_data);
-       const unsigned int strength_4_8[] = {4, 8};
-       const unsigned int strength_8_12_16_20[] = {8, 12, 16, 20};
+       enum uniphier_pin_drv_type type =
+                               uniphier_pin_get_drv_type(desc->drv_data);
+       const unsigned int strength_1bit[] = {4, 8};
+       const unsigned int strength_2bit[] = {8, 12, 16, 20};
+       const unsigned int strength_3bit[] = {4, 5, 7, 9, 11, 12, 14, 16};
        const unsigned int *supported_strength;
        unsigned int drvctrl, reg, shift, mask, width, val;
        int ret;
 
-       switch (drv_str) {
-       case UNIPHIER_PIN_DRV_4_8:
-               supported_strength = strength_4_8;
+       switch (type) {
+       case UNIPHIER_PIN_DRV_1BIT:
+               supported_strength = strength_1bit;
+               reg = UNIPHIER_PINCTRL_DRVCTRL_BASE;
                width = 1;
                break;
-       case UNIPHIER_PIN_DRV_8_12_16_20:
-               supported_strength = strength_8_12_16_20;
+       case UNIPHIER_PIN_DRV_2BIT:
+               supported_strength = strength_2bit;
+               reg = UNIPHIER_PINCTRL_DRV2CTRL_BASE;
                width = 2;
                break;
-       case UNIPHIER_PIN_DRV_FIXED_4:
+       case UNIPHIER_PIN_DRV_3BIT:
+               supported_strength = strength_3bit;
+               reg = UNIPHIER_PINCTRL_DRV3CTRL_BASE;
+               width = 4;
+               break;
+       case UNIPHIER_PIN_DRV_FIXED4:
                *strength = 4;
                return 0;
-       case UNIPHIER_PIN_DRV_FIXED_5:
+       case UNIPHIER_PIN_DRV_FIXED5:
                *strength = 5;
                return 0;
-       case UNIPHIER_PIN_DRV_FIXED_8:
+       case UNIPHIER_PIN_DRV_FIXED8:
                *strength = 8;
                return 0;
        default:
@@ -204,17 +224,14 @@ static int uniphier_conf_pin_drive_get(struct pinctrl_dev *pctldev,
                return -EINVAL;
        }
 
-       drvctrl = uniphier_pin_get_drvctrl(pin->drv_data);
+       drvctrl = uniphier_pin_get_drvctrl(desc->drv_data);
        drvctrl *= width;
 
-       reg = (width == 2) ? UNIPHIER_PINCTRL_DRV2CTRL_BASE :
-                            UNIPHIER_PINCTRL_DRVCTRL_BASE;
-
        reg += drvctrl / 32 * 4;
        shift = drvctrl % 32;
        mask = (1U << width) - 1;
 
-       ret = regmap_read(priv->regmap, reg, &val);
+       ret = regmap_read(priv->regmap, priv->regbase + reg, &val);
        if (ret)
                return ret;
 
@@ -224,10 +241,10 @@ static int uniphier_conf_pin_drive_get(struct pinctrl_dev *pctldev,
 }
 
 static int uniphier_conf_pin_input_enable_get(struct pinctrl_dev *pctldev,
-                                       const struct pinctrl_pin_desc *pin)
+                                             const struct pin_desc *desc)
 {
        struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
-       unsigned int iectrl = uniphier_pin_get_iectrl(pin->drv_data);
+       unsigned int iectrl = uniphier_pin_get_iectrl(desc->drv_data);
        unsigned int val;
        int ret;
 
@@ -235,7 +252,8 @@ static int uniphier_conf_pin_input_enable_get(struct pinctrl_dev *pctldev,
                /* This pin is always input-enabled. */
                return 0;
 
-       ret = regmap_read(priv->regmap, UNIPHIER_PINCTRL_IECTRL, &val);
+       ret = regmap_read(priv->regmap,
+                         priv->regbase + UNIPHIER_PINCTRL_IECTRL, &val);
        if (ret)
                return ret;
 
@@ -246,7 +264,7 @@ static int uniphier_conf_pin_config_get(struct pinctrl_dev *pctldev,
                                        unsigned pin,
                                        unsigned long *configs)
 {
-       const struct pinctrl_pin_desc *pin_desc = &pctldev->desc->pins[pin];
+       const struct pin_desc *desc = pin_desc_get(pctldev, pin);
        enum pin_config_param param = pinconf_to_config_param(*configs);
        bool has_arg = false;
        u16 arg;
@@ -256,14 +274,14 @@ static int uniphier_conf_pin_config_get(struct pinctrl_dev *pctldev,
        case PIN_CONFIG_BIAS_DISABLE:
        case PIN_CONFIG_BIAS_PULL_UP:
        case PIN_CONFIG_BIAS_PULL_DOWN:
-               ret = uniphier_conf_pin_bias_get(pctldev, pin_desc, param);
+               ret = uniphier_conf_pin_bias_get(pctldev, desc, param);
                break;
        case PIN_CONFIG_DRIVE_STRENGTH:
-               ret = uniphier_conf_pin_drive_get(pctldev, pin_desc, &arg);
+               ret = uniphier_conf_pin_drive_get(pctldev, desc, &arg);
                has_arg = true;
                break;
        case PIN_CONFIG_INPUT_ENABLE:
-               ret = uniphier_conf_pin_input_enable_get(pctldev, pin_desc);
+               ret = uniphier_conf_pin_input_enable_get(pctldev, desc);
                break;
        default:
                /* unsupported parameter */
@@ -278,13 +296,12 @@ static int uniphier_conf_pin_config_get(struct pinctrl_dev *pctldev,
 }
 
 static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev,
-                                     const struct pinctrl_pin_desc *pin,
-                                     enum pin_config_param param,
-                                     u16 arg)
+                                     const struct pin_desc *desc,
+                                     enum pin_config_param param, u16 arg)
 {
        struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
        enum uniphier_pin_pull_dir pull_dir =
-                               uniphier_pin_get_pull_dir(pin->drv_data);
+                               uniphier_pin_get_pull_dir(desc->drv_data);
        unsigned int pupdctrl, reg, shift;
        unsigned int val = 1;
 
@@ -295,8 +312,8 @@ static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev,
                if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED ||
                    pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) {
                        dev_err(pctldev->dev,
-                               "can not disable pull register for pin %u (%s)\n",
-                               pin->number, pin->name);
+                               "can not disable pull register for pin %s\n",
+                               desc->name);
                        return -EINVAL;
                }
                val = 0;
@@ -306,8 +323,8 @@ static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev,
                        return 0;
                if (pull_dir != UNIPHIER_PIN_PULL_UP) {
                        dev_err(pctldev->dev,
-                               "pull-up is unsupported for pin %u (%s)\n",
-                               pin->number, pin->name);
+                               "pull-up is unsupported for pin %s\n",
+                               desc->name);
                        return -EINVAL;
                }
                if (arg == 0) {
@@ -320,8 +337,8 @@ static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev,
                        return 0;
                if (pull_dir != UNIPHIER_PIN_PULL_DOWN) {
                        dev_err(pctldev->dev,
-                               "pull-down is unsupported for pin %u (%s)\n",
-                               pin->number, pin->name);
+                               "pull-down is unsupported for pin %s\n",
+                               desc->name);
                        return -EINVAL;
                }
                if (arg == 0) {
@@ -332,8 +349,8 @@ static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev,
        case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
                if (pull_dir == UNIPHIER_PIN_PULL_NONE) {
                        dev_err(pctldev->dev,
-                               "pull-up/down is unsupported for pin %u (%s)\n",
-                               pin->number, pin->name);
+                               "pull-up/down is unsupported for pin %s\n",
+                               desc->name);
                        return -EINVAL;
                }
 
@@ -344,39 +361,48 @@ static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev,
                BUG();
        }
 
-       pupdctrl = uniphier_pin_get_pupdctrl(pin->drv_data);
+       pupdctrl = uniphier_pin_get_pupdctrl(desc->drv_data);
 
        reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pupdctrl / 32 * 4;
        shift = pupdctrl % 32;
 
-       return regmap_update_bits(priv->regmap, reg, 1 << shift, val << shift);
+       return regmap_update_bits(priv->regmap, priv->regbase + reg,
+                                 1 << shift, val << shift);
 }
 
 static int uniphier_conf_pin_drive_set(struct pinctrl_dev *pctldev,
-                                      const struct pinctrl_pin_desc *pin,
+                                      const struct pin_desc *desc,
                                       u16 strength)
 {
        struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
-       enum uniphier_pin_drv_str drv_str =
-                               uniphier_pin_get_drv_str(pin->drv_data);
-       const unsigned int strength_4_8[] = {4, 8, -1};
-       const unsigned int strength_8_12_16_20[] = {8, 12, 16, 20, -1};
+       enum uniphier_pin_drv_type type =
+                               uniphier_pin_get_drv_type(desc->drv_data);
+       const unsigned int strength_1bit[] = {4, 8, -1};
+       const unsigned int strength_2bit[] = {8, 12, 16, 20, -1};
+       const unsigned int strength_3bit[] = {4, 5, 7, 9, 11, 12, 14, 16, -1};
        const unsigned int *supported_strength;
        unsigned int drvctrl, reg, shift, mask, width, val;
 
-       switch (drv_str) {
-       case UNIPHIER_PIN_DRV_4_8:
-               supported_strength = strength_4_8;
+       switch (type) {
+       case UNIPHIER_PIN_DRV_1BIT:
+               supported_strength = strength_1bit;
+               reg = UNIPHIER_PINCTRL_DRVCTRL_BASE;
                width = 1;
                break;
-       case UNIPHIER_PIN_DRV_8_12_16_20:
-               supported_strength = strength_8_12_16_20;
+       case UNIPHIER_PIN_DRV_2BIT:
+               supported_strength = strength_2bit;
+               reg = UNIPHIER_PINCTRL_DRV2CTRL_BASE;
                width = 2;
                break;
+       case UNIPHIER_PIN_DRV_3BIT:
+               supported_strength = strength_3bit;
+               reg = UNIPHIER_PINCTRL_DRV3CTRL_BASE;
+               width = 4;
+               break;
        default:
                dev_err(pctldev->dev,
-                       "cannot change drive strength for pin %u (%s)\n",
-                       pin->number, pin->name);
+                       "cannot change drive strength for pin %s\n",
+                       desc->name);
                return -EINVAL;
        }
 
@@ -387,49 +413,48 @@ static int uniphier_conf_pin_drive_set(struct pinctrl_dev *pctldev,
 
        if (val == 0) {
                dev_err(pctldev->dev,
-                       "unsupported drive strength %u mA for pin %u (%s)\n",
-                       strength, pin->number, pin->name);
+                       "unsupported drive strength %u mA for pin %s\n",
+                       strength, desc->name);
                return -EINVAL;
        }
 
        val--;
 
-       drvctrl = uniphier_pin_get_drvctrl(pin->drv_data);
+       drvctrl = uniphier_pin_get_drvctrl(desc->drv_data);
        drvctrl *= width;
 
-       reg = (width == 2) ? UNIPHIER_PINCTRL_DRV2CTRL_BASE :
-                            UNIPHIER_PINCTRL_DRVCTRL_BASE;
-
        reg += drvctrl / 32 * 4;
        shift = drvctrl % 32;
        mask = (1U << width) - 1;
 
-       return regmap_update_bits(priv->regmap, reg,
+       return regmap_update_bits(priv->regmap, priv->regbase + reg,
                                  mask << shift, val << shift);
 }
 
 static int uniphier_conf_pin_input_enable(struct pinctrl_dev *pctldev,
-                                         const struct pinctrl_pin_desc *pin,
+                                         const struct pin_desc *desc,
                                          u16 enable)
 {
        struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
-       unsigned int iectrl = uniphier_pin_get_iectrl(pin->drv_data);
+       unsigned int iectrl = uniphier_pin_get_iectrl(desc->drv_data);
+       unsigned int reg, mask;
 
-       if (enable == 0) {
-               /*
-                * Multiple pins share one input enable, so per-pin disabling
-                * is impossible.
-                */
-               dev_err(pctldev->dev, "unable to disable input\n");
+       /*
+        * Multiple pins share one input enable, per-pin disabling is
+        * impossible.
+        */
+       if (!(priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL) &&
+           !enable)
                return -EINVAL;
-       }
 
+       /* UNIPHIER_PIN_IECTRL_NONE means the pin is always input-enabled */
        if (iectrl == UNIPHIER_PIN_IECTRL_NONE)
-               /* This pin is always input-enabled. nothing to do. */
-               return 0;
+               return enable ? 0 : -EINVAL;
+
+       reg = priv->regbase + UNIPHIER_PINCTRL_IECTRL + iectrl / 32 * 4;
+       mask = BIT(iectrl % 32);
 
-       return regmap_update_bits(priv->regmap, UNIPHIER_PINCTRL_IECTRL,
-                                 BIT(iectrl), BIT(iectrl));
+       return regmap_update_bits(priv->regmap, reg, mask, enable ? mask : 0);
 }
 
 static int uniphier_conf_pin_config_set(struct pinctrl_dev *pctldev,
@@ -437,7 +462,7 @@ static int uniphier_conf_pin_config_set(struct pinctrl_dev *pctldev,
                                        unsigned long *configs,
                                        unsigned num_configs)
 {
-       const struct pinctrl_pin_desc *pin_desc = &pctldev->desc->pins[pin];
+       const struct pin_desc *desc = pin_desc_get(pctldev, pin);
        int i, ret;
 
        for (i = 0; i < num_configs; i++) {
@@ -450,16 +475,15 @@ static int uniphier_conf_pin_config_set(struct pinctrl_dev *pctldev,
                case PIN_CONFIG_BIAS_PULL_UP:
                case PIN_CONFIG_BIAS_PULL_DOWN:
                case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
-                       ret = uniphier_conf_pin_bias_set(pctldev, pin_desc,
+                       ret = uniphier_conf_pin_bias_set(pctldev, desc,
                                                         param, arg);
                        break;
                case PIN_CONFIG_DRIVE_STRENGTH:
-                       ret = uniphier_conf_pin_drive_set(pctldev, pin_desc,
-                                                         arg);
+                       ret = uniphier_conf_pin_drive_set(pctldev, desc, arg);
                        break;
                case PIN_CONFIG_INPUT_ENABLE:
-                       ret = uniphier_conf_pin_input_enable(pctldev,
-                                                            pin_desc, arg);
+                       ret = uniphier_conf_pin_input_enable(pctldev, desc,
+                                                            arg);
                        break;
                default:
                        dev_err(pctldev->dev,
@@ -531,20 +555,42 @@ static int uniphier_pmx_get_function_groups(struct pinctrl_dev *pctldev,
 }
 
 static int uniphier_pmx_set_one_mux(struct pinctrl_dev *pctldev, unsigned pin,
-                                   unsigned muxval)
+                                   int muxval)
 {
        struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
-       unsigned mux_bits = priv->socdata->mux_bits;
-       unsigned reg_stride = priv->socdata->reg_stride;
-       unsigned reg, reg_end, shift, mask;
+       unsigned int mux_bits, reg_stride, reg, reg_end, shift, mask;
+       bool load_pinctrl;
        int ret;
 
        /* some pins need input-enabling */
        ret = uniphier_conf_pin_input_enable(pctldev,
-                                            &pctldev->desc->pins[pin], 1);
+                                            pin_desc_get(pctldev, pin), 1);
        if (ret)
                return ret;
 
+       if (muxval < 0)
+               return 0;       /* dedicated pin; nothing to do for pin-mux */
+
+       if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_DBGMUX_SEPARATE) {
+               /*
+                *  Mode     reg_offset     bit_position
+                *  Normal    4 * n        shift+3:shift
+                *  Debug     4 * n        shift+7:shift+4
+                */
+               mux_bits = 4;
+               reg_stride = 8;
+               load_pinctrl = true;
+       } else {
+               /*
+                *  Mode     reg_offset     bit_position
+                *  Normal    8 * n        shift+3:shift
+                *  Debug     8 * n + 4    shift+3:shift
+                */
+               mux_bits = 8;
+               reg_stride = 4;
+               load_pinctrl = false;
+       }
+
        reg = UNIPHIER_PINCTRL_PINMUX_BASE + pin * mux_bits / 32 * reg_stride;
        reg_end = reg + reg_stride;
        shift = pin * mux_bits % 32;
@@ -555,16 +601,17 @@ static int uniphier_pmx_set_one_mux(struct pinctrl_dev *pctldev, unsigned pin,
         * stored in the offset+4.
         */
        for (; reg < reg_end; reg += 4) {
-               ret = regmap_update_bits(priv->regmap, reg,
+               ret = regmap_update_bits(priv->regmap, priv->regbase + reg,
                                         mask << shift, muxval << shift);
                if (ret)
                        return ret;
                muxval >>= mux_bits;
        }
 
-       if (priv->socdata->load_pinctrl) {
+       if (load_pinctrl) {
                ret = regmap_write(priv->regmap,
-                                  UNIPHIER_PINCTRL_LOAD_PINMUX, 1);
+                                  priv->regbase + UNIPHIER_PINCTRL_LOAD_PINMUX,
+                                  1);
                if (ret)
                        return ret;
        }
@@ -633,19 +680,16 @@ static const struct pinmux_ops uniphier_pmxops = {
 };
 
 int uniphier_pinctrl_probe(struct platform_device *pdev,
-                          struct pinctrl_desc *desc,
                           struct uniphier_pinctrl_socdata *socdata)
 {
        struct device *dev = &pdev->dev;
        struct uniphier_pinctrl_priv *priv;
+       struct device_node *parent;
 
        if (!socdata ||
-           !socdata->groups ||
-           !socdata->groups_count ||
-           !socdata->functions ||
-           !socdata->functions_count ||
-           !socdata->mux_bits ||
-           !socdata->reg_stride) {
+           !socdata->pins || !socdata->npins ||
+           !socdata->groups || !socdata->groups_count ||
+           !socdata->functions || !socdata->functions_count) {
                dev_err(dev, "pinctrl socdata lacks necessary members\n");
                return -EINVAL;
        }
@@ -654,18 +698,36 @@ int uniphier_pinctrl_probe(struct platform_device *pdev,
        if (!priv)
                return -ENOMEM;
 
-       priv->regmap = syscon_node_to_regmap(dev->of_node);
+       if (of_device_is_compatible(dev->of_node, "socionext,ph1-ld4-pinctrl") ||
+           of_device_is_compatible(dev->of_node, "socionext,ph1-pro4-pinctrl") ||
+           of_device_is_compatible(dev->of_node, "socionext,ph1-sld8-pinctrl") ||
+           of_device_is_compatible(dev->of_node, "socionext,ph1-pro5-pinctrl") ||
+           of_device_is_compatible(dev->of_node, "socionext,proxstream2-pinctrl") ||
+           of_device_is_compatible(dev->of_node, "socionext,ph1-ld6b-pinctrl")) {
+               /* old binding */
+               priv->regmap = syscon_node_to_regmap(dev->of_node);
+       } else {
+               priv->regbase = 0x1000;
+               parent = of_get_parent(dev->of_node);
+               priv->regmap = syscon_node_to_regmap(parent);
+               of_node_put(parent);
+       }
+
        if (IS_ERR(priv->regmap)) {
                dev_err(dev, "failed to get regmap\n");
                return PTR_ERR(priv->regmap);
        }
 
        priv->socdata = socdata;
-       desc->pctlops = &uniphier_pctlops;
-       desc->pmxops = &uniphier_pmxops;
-       desc->confops = &uniphier_confops;
-
-       priv->pctldev = devm_pinctrl_register(dev, desc, priv);
+       priv->pctldesc.name = dev->driver->name;
+       priv->pctldesc.pins = socdata->pins;
+       priv->pctldesc.npins = socdata->npins;
+       priv->pctldesc.pctlops = &uniphier_pctlops;
+       priv->pctldesc.pmxops = &uniphier_pmxops;
+       priv->pctldesc.confops = &uniphier_confops;
+       priv->pctldesc.owner = dev->driver->owner;
+
+       priv->pctldev = devm_pinctrl_register(dev, &priv->pctldesc, priv);
        if (IS_ERR(priv->pctldev)) {
                dev_err(dev, "failed to register UniPhier pinctrl driver\n");
                return PTR_ERR(priv->pctldev);
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld11.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld11.c
new file mode 100644 (file)
index 0000000..77a0236
--- /dev/null
@@ -0,0 +1,952 @@
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-uniphier.h"
+
+static const struct pinctrl_pin_desc uniphier_ld11_pins[] = {
+       UNIPHIER_PINCTRL_PIN(0, "XECS1", 0,
+                            0, UNIPHIER_PIN_DRV_1BIT,
+                            0, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(1, "ERXW", UNIPHIER_PIN_IECTRL_NONE,
+                            1, UNIPHIER_PIN_DRV_1BIT,
+                            1, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(2, "XERWE1", UNIPHIER_PIN_IECTRL_NONE,
+                            2, UNIPHIER_PIN_DRV_1BIT,
+                            2, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(3, "XNFWP", 3,
+                            3, UNIPHIER_PIN_DRV_1BIT,
+                            3, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(4, "XNFCE0", 4,
+                            4, UNIPHIER_PIN_DRV_1BIT,
+                            4, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(5, "NFRYBY0", 5,
+                            5, UNIPHIER_PIN_DRV_1BIT,
+                            5, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(6, "XNFRE", UNIPHIER_PIN_IECTRL_NONE,
+                            6, UNIPHIER_PIN_DRV_1BIT,
+                            6, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(7, "XNFWE", UNIPHIER_PIN_IECTRL_NONE,
+                            7, UNIPHIER_PIN_DRV_1BIT,
+                            7, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(8, "NFALE", UNIPHIER_PIN_IECTRL_NONE,
+                            8, UNIPHIER_PIN_DRV_1BIT,
+                            8, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(9, "NFCLE", UNIPHIER_PIN_IECTRL_NONE,
+                            9, UNIPHIER_PIN_DRV_1BIT,
+                            9, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(10, "NFD0", 10,
+                            10, UNIPHIER_PIN_DRV_1BIT,
+                            10, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(11, "NFD1", 11,
+                            11, UNIPHIER_PIN_DRV_1BIT,
+                            11, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(12, "NFD2", 12,
+                            12, UNIPHIER_PIN_DRV_1BIT,
+                            12, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(13, "NFD3", 13,
+                            13, UNIPHIER_PIN_DRV_1BIT,
+                            13, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(14, "NFD4", 14,
+                            14, UNIPHIER_PIN_DRV_1BIT,
+                            14, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(15, "NFD5", 15,
+                            15, UNIPHIER_PIN_DRV_1BIT,
+                            15, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(16, "NFD6", 16,
+                            16, UNIPHIER_PIN_DRV_1BIT,
+                            16, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(17, "NFD7", 17,
+                            17, UNIPHIER_PIN_DRV_1BIT,
+                            17, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(18, "XERST", 18,
+                            0, UNIPHIER_PIN_DRV_2BIT,
+                            18, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(19, "MMCCLK", 19,
+                            1, UNIPHIER_PIN_DRV_2BIT,
+                            19, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(20, "MMCCMD", 20,
+                            2, UNIPHIER_PIN_DRV_2BIT,
+                            20, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(21, "MMCDS", 21,
+                            3, UNIPHIER_PIN_DRV_2BIT,
+                            21, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(22, "MMCDAT0", 22,
+                            4, UNIPHIER_PIN_DRV_2BIT,
+                            22, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(23, "MMCDAT1", 23,
+                            5, UNIPHIER_PIN_DRV_2BIT,
+                            23, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(24, "MMCDAT2", 24,
+                            6, UNIPHIER_PIN_DRV_2BIT,
+                            24, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(25, "MMCDAT3", 25,
+                            7, UNIPHIER_PIN_DRV_2BIT,
+                            25, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(26, "MMCDAT4", 26,
+                            8, UNIPHIER_PIN_DRV_2BIT,
+                            26, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(27, "MMCDAT5", 27,
+                            9, UNIPHIER_PIN_DRV_2BIT,
+                            27, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(28, "MMCDAT6", 28,
+                            10, UNIPHIER_PIN_DRV_2BIT,
+                            28, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(29, "MMCDAT7", 29,
+                            11, UNIPHIER_PIN_DRV_2BIT,
+                            29, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(46, "USB0VBUS", 46,
+                            46, UNIPHIER_PIN_DRV_1BIT,
+                            46, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(47, "USB0OD", UNIPHIER_PIN_IECTRL_NONE,
+                            47, UNIPHIER_PIN_DRV_1BIT,
+                            47, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(48, "USB1VBUS", 48,
+                            48, UNIPHIER_PIN_DRV_1BIT,
+                            48, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(49, "USB1OD", 49,
+                            49, UNIPHIER_PIN_DRV_1BIT,
+                            49, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(50, "USB2VBUS", 50,
+                            50, UNIPHIER_PIN_DRV_1BIT,
+                            50, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(51, "USB2OD", 51,
+                            51, UNIPHIER_PIN_DRV_1BIT,
+                            51, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(54, "TXD0", 54,
+                            54, UNIPHIER_PIN_DRV_1BIT,
+                            54, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(55, "RXD0", 55,
+                            55, UNIPHIER_PIN_DRV_1BIT,
+                            55, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(56, "SPISYNC0", 56,
+                            56, UNIPHIER_PIN_DRV_1BIT,
+                            56, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(57, "SPISCLK0", 57,
+                            57, UNIPHIER_PIN_DRV_1BIT,
+                            57, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(58, "SPITXD0", 58,
+                            58, UNIPHIER_PIN_DRV_1BIT,
+                            58, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(59, "SPIRXD0", 59,
+                            59, UNIPHIER_PIN_DRV_1BIT,
+                            59, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(60, "AGCI", 60,
+                            60, UNIPHIER_PIN_DRV_1BIT,
+                            60, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(61, "DMDSDA0", 61,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(62, "DMDSCL0", 62,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(63, "SDA0", 63,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(64, "SCL0", 64,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(65, "SDA1", 65,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(66, "SCL1", 66,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(67, "HIN", 67,
+                            -1, UNIPHIER_PIN_DRV_FIXED5,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(68, "VIN", 68,
+                            -1, UNIPHIER_PIN_DRV_FIXED5,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(69, "PCA00", 69,
+                            69, UNIPHIER_PIN_DRV_1BIT,
+                            69, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(70, "PCA01", 70,
+                            70, UNIPHIER_PIN_DRV_1BIT,
+                            70, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(71, "PCA02", 71,
+                            71, UNIPHIER_PIN_DRV_1BIT,
+                            71, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(72, "PCA03", 72,
+                            72, UNIPHIER_PIN_DRV_1BIT,
+                            72, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(73, "PCA04", 73,
+                            73, UNIPHIER_PIN_DRV_1BIT,
+                            73, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(74, "PCA05", 74,
+                            74, UNIPHIER_PIN_DRV_1BIT,
+                            74, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(75, "PCA06", 75,
+                            75, UNIPHIER_PIN_DRV_1BIT,
+                            75, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(76, "PCA07", 76,
+                            76, UNIPHIER_PIN_DRV_1BIT,
+                            76, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(77, "PCA08", 77,
+                            77, UNIPHIER_PIN_DRV_1BIT,
+                            77, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(78, "PCA09", 78,
+                            78, UNIPHIER_PIN_DRV_1BIT,
+                            78, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(79, "PCA10", 79,
+                            79, UNIPHIER_PIN_DRV_1BIT,
+                            79, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(80, "PCA11", 80,
+                            80, UNIPHIER_PIN_DRV_1BIT,
+                            80, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(81, "PCA12", 81,
+                            81, UNIPHIER_PIN_DRV_1BIT,
+                            81, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(82, "PCA13", 82,
+                            82, UNIPHIER_PIN_DRV_1BIT,
+                            82, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(83, "PCA14", 83,
+                            83, UNIPHIER_PIN_DRV_1BIT,
+                            83, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(84, "PC0READY", 84,
+                            84, UNIPHIER_PIN_DRV_1BIT,
+                            84, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(85, "PC0CD1", 85,
+                            85, UNIPHIER_PIN_DRV_1BIT,
+                            85, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(86, "PC0CD2", 86,
+                            86, UNIPHIER_PIN_DRV_1BIT,
+                            86, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(87, "PC0WAIT", 87,
+                            87, UNIPHIER_PIN_DRV_1BIT,
+                            87, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(88, "PC0RESET", 88,
+                            88, UNIPHIER_PIN_DRV_1BIT,
+                            88, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(89, "PC0CE1", 89,
+                            89, UNIPHIER_PIN_DRV_1BIT,
+                            89, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(90, "PC0WE", 90,
+                            90, UNIPHIER_PIN_DRV_1BIT,
+                            90, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(91, "PC0OE", 91,
+                            91, UNIPHIER_PIN_DRV_1BIT,
+                            91, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(92, "PC0IOWR", 92,
+                            92, UNIPHIER_PIN_DRV_1BIT,
+                            92, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(93, "PC0IORD", 93,
+                            93, UNIPHIER_PIN_DRV_1BIT,
+                            93, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(94, "PCD00", 94,
+                            94, UNIPHIER_PIN_DRV_1BIT,
+                            94, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(95, "PCD01", 95,
+                            95, UNIPHIER_PIN_DRV_1BIT,
+                            95, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(96, "PCD02", 96,
+                            96, UNIPHIER_PIN_DRV_1BIT,
+                            96, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(97, "PCD03", 97,
+                            97, UNIPHIER_PIN_DRV_1BIT,
+                            97, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(98, "PCD04", 98,
+                            98, UNIPHIER_PIN_DRV_1BIT,
+                            98, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(99, "PCD05", 99,
+                            99, UNIPHIER_PIN_DRV_1BIT,
+                            99, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(100, "PCD06", 100,
+                            100, UNIPHIER_PIN_DRV_1BIT,
+                            100, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(101, "PCD07", 101,
+                            101, UNIPHIER_PIN_DRV_1BIT,
+                            101, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(102, "HS0BCLKIN", 102,
+                            102, UNIPHIER_PIN_DRV_1BIT,
+                            102, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(103, "HS0SYNCIN", 103,
+                            103, UNIPHIER_PIN_DRV_1BIT,
+                            103, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(104, "HS0VALIN", 104,
+                            104, UNIPHIER_PIN_DRV_1BIT,
+                            104, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(105, "HS0DIN0", 105,
+                            105, UNIPHIER_PIN_DRV_1BIT,
+                            105, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(106, "HS0DIN1", 106,
+                            106, UNIPHIER_PIN_DRV_1BIT,
+                            106, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(107, "HS0DIN2", 107,
+                            107, UNIPHIER_PIN_DRV_1BIT,
+                            107, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(108, "HS0DIN3", 108,
+                            108, UNIPHIER_PIN_DRV_1BIT,
+                            108, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(109, "HS0DIN4", 109,
+                            109, UNIPHIER_PIN_DRV_1BIT,
+                            109, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(110, "HS0DIN5", 110,
+                            110, UNIPHIER_PIN_DRV_1BIT,
+                            110, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(111, "HS0DIN6", 111,
+                            111, UNIPHIER_PIN_DRV_1BIT,
+                            111, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(112, "HS0DIN7", 112,
+                            112, UNIPHIER_PIN_DRV_1BIT,
+                            112, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(113, "HS0BCLKOUT", 113,
+                            113, UNIPHIER_PIN_DRV_1BIT,
+                            113, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(114, "HS0SYNCOUT", 114,
+                            114, UNIPHIER_PIN_DRV_1BIT,
+                            114, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(115, "HS0VALOUT", 115,
+                            115, UNIPHIER_PIN_DRV_1BIT,
+                            115, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(116, "HS0DOUT0", 116,
+                            116, UNIPHIER_PIN_DRV_1BIT,
+                            116, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(117, "HS0DOUT1", 117,
+                            117, UNIPHIER_PIN_DRV_1BIT,
+                            117, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(118, "HS0DOUT2", 118,
+                            118, UNIPHIER_PIN_DRV_1BIT,
+                            118, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(119, "HS0DOUT3", 119,
+                            119, UNIPHIER_PIN_DRV_1BIT,
+                            119, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(120, "HS0DOUT4", 120,
+                            120, UNIPHIER_PIN_DRV_1BIT,
+                            120, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(121, "HS0DOUT5", 121,
+                            121, UNIPHIER_PIN_DRV_1BIT,
+                            121, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(122, "HS0DOUT6", 122,
+                            122, UNIPHIER_PIN_DRV_1BIT,
+                            122, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(123, "HS0DOUT7", 123,
+                            123, UNIPHIER_PIN_DRV_1BIT,
+                            123, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(124, "HS1BCLKIN", 124,
+                            124, UNIPHIER_PIN_DRV_1BIT,
+                            124, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(125, "HS1SYNCIN", 125,
+                            125, UNIPHIER_PIN_DRV_1BIT,
+                            125, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(126, "HS1VALIN", 126,
+                            126, UNIPHIER_PIN_DRV_1BIT,
+                            126, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(127, "HS1DIN0", 127,
+                            127, UNIPHIER_PIN_DRV_1BIT,
+                            127, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(128, "HS1DIN1", 128,
+                            128, UNIPHIER_PIN_DRV_1BIT,
+                            128, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(129, "HS1DIN2", 129,
+                            129, UNIPHIER_PIN_DRV_1BIT,
+                            129, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(130, "HS1DIN3", 130,
+                            130, UNIPHIER_PIN_DRV_1BIT,
+                            130, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(131, "HS1DIN4", 131,
+                            131, UNIPHIER_PIN_DRV_1BIT,
+                            131, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(132, "HS1DIN5", 132,
+                            132, UNIPHIER_PIN_DRV_1BIT,
+                            132, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(133, "HS1DIN6", 133,
+                            133, UNIPHIER_PIN_DRV_1BIT,
+                            133, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(134, "HS1DIN7", 134,
+                            134, UNIPHIER_PIN_DRV_1BIT,
+                            134, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(135, "AO1IEC", 135,
+                            135, UNIPHIER_PIN_DRV_1BIT,
+                            135, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(136, "AO1ARC", 136,
+                            136, UNIPHIER_PIN_DRV_1BIT,
+                            136, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(137, "AO1DACCK", 137,
+                            137, UNIPHIER_PIN_DRV_1BIT,
+                            137, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(138, "AO1BCK", 138,
+                            138, UNIPHIER_PIN_DRV_1BIT,
+                            138, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(139, "AO1LRCK", 139,
+                            139, UNIPHIER_PIN_DRV_1BIT,
+                            139, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(140, "AO1D0", 140,
+                            140, UNIPHIER_PIN_DRV_1BIT,
+                            140, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(141, "TCON0", 141,
+                            141, UNIPHIER_PIN_DRV_1BIT,
+                            141, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(142, "TCON1", 142,
+                            142, UNIPHIER_PIN_DRV_1BIT,
+                            142, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(143, "TCON2", 143,
+                            143, UNIPHIER_PIN_DRV_1BIT,
+                            143, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(144, "TCON3", 144,
+                            144, UNIPHIER_PIN_DRV_1BIT,
+                            144, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(145, "TCON4", 145,
+                            145, UNIPHIER_PIN_DRV_1BIT,
+                            145, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(146, "TCON5", 146,
+                            146, UNIPHIER_PIN_DRV_1BIT,
+                            146, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(147, "PWMA", 147,
+                            147, UNIPHIER_PIN_DRV_1BIT,
+                            147, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(148, "LR_GOUT", 148,
+                            148, UNIPHIER_PIN_DRV_1BIT,
+                            148, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(149, "XIRQ0", 149,
+                            149, UNIPHIER_PIN_DRV_1BIT,
+                            149, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(150, "XIRQ1", 150,
+                            150, UNIPHIER_PIN_DRV_1BIT,
+                            150, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(151, "XIRQ2", 151,
+                            151, UNIPHIER_PIN_DRV_1BIT,
+                            151, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(152, "XIRQ3", 152,
+                            152, UNIPHIER_PIN_DRV_1BIT,
+                            152, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(153, "XIRQ4", 153,
+                            153, UNIPHIER_PIN_DRV_1BIT,
+                            153, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(154, "XIRQ5", 154,
+                            154, UNIPHIER_PIN_DRV_1BIT,
+                            154, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(155, "XIRQ6", 155,
+                            155, UNIPHIER_PIN_DRV_1BIT,
+                            155, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(156, "XIRQ7", 156,
+                            156, UNIPHIER_PIN_DRV_1BIT,
+                            156, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(157, "XIRQ8", 157,
+                            157, UNIPHIER_PIN_DRV_1BIT,
+                            157, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(158, "AGCBS", 158,
+                            158, UNIPHIER_PIN_DRV_1BIT,
+                            158, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(159, "XIRQ21", 159,
+                            159, UNIPHIER_PIN_DRV_1BIT,
+                            159, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(160, "XIRQ22", 160,
+                            160, UNIPHIER_PIN_DRV_1BIT,
+                            160, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(161, "XIRQ23", 161,
+                            161, UNIPHIER_PIN_DRV_1BIT,
+                            161, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(162, "CH2CLK", 162,
+                            162, UNIPHIER_PIN_DRV_1BIT,
+                            162, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(163, "CH2PSYNC", 163,
+                            163, UNIPHIER_PIN_DRV_1BIT,
+                            163, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(164, "CH2VAL", 164,
+                            164, UNIPHIER_PIN_DRV_1BIT,
+                            164, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(165, "CH2DATA", 165,
+                            165, UNIPHIER_PIN_DRV_1BIT,
+                            165, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(166, "CK25O", 166,
+                            166, UNIPHIER_PIN_DRV_1BIT,
+                            166, UNIPHIER_PIN_PULL_DOWN),
+};
+
+static const unsigned emmc_pins[] = {18, 19, 20, 21, 22, 23, 24, 25};
+static const int emmc_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned emmc_dat8_pins[] = {26, 27, 28, 29};
+static const int emmc_dat8_muxvals[] = {0, 0, 0, 0};
+static const unsigned ether_rmii_pins[] = {6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+                                          16, 17};
+static const int ether_rmii_muxvals[] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4};
+static const unsigned i2c0_pins[] = {63, 64};
+static const int i2c0_muxvals[] = {0, 0};
+static const unsigned i2c1_pins[] = {65, 66};
+static const int i2c1_muxvals[] = {0, 0};
+static const unsigned i2c3_pins[] = {67, 68};
+static const int i2c3_muxvals[] = {1, 1};
+static const unsigned i2c4_pins[] = {61, 62};
+static const int i2c4_muxvals[] = {1, 1};
+static const unsigned nand_pins[] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+                                    15, 16, 17};
+static const int nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned system_bus_pins[] = {1, 2, 6, 7, 8, 9, 10, 11, 12, 13,
+                                          14, 15, 16, 17};
+static const int system_bus_muxvals[] = {0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+                                        2};
+static const unsigned system_bus_cs1_pins[] = {0};
+static const int system_bus_cs1_muxvals[] = {0};
+static const unsigned uart0_pins[] = {54, 55};
+static const int uart0_muxvals[] = {0, 0};
+static const unsigned uart1_pins[] = {58, 59};
+static const int uart1_muxvals[] = {1, 1};
+static const unsigned uart2_pins[] = {90, 91};
+static const int uart2_muxvals[] = {1, 1};
+static const unsigned uart3_pins[] = {94, 95};
+static const int uart3_muxvals[] = {1, 1};
+static const unsigned usb0_pins[] = {46, 47};
+static const int usb0_muxvals[] = {0, 0};
+static const unsigned usb1_pins[] = {48, 49};
+static const int usb1_muxvals[] = {0, 0};
+static const unsigned usb2_pins[] = {50, 51};
+static const int usb2_muxvals[] = {0, 0};
+static const unsigned port_range_pins[] = {
+       159, 160, 161, 162, 163, 164, 165, 166,         /* PORT0x */
+       0, 1, 2, 3, 4, 5, 6, 7,                         /* PORT1x */
+       8, 9, 10, 11, 12, 13, 14, 15,                   /* PORT2x */
+       16, 17, 18, -1, -1, -1, -1, -1,                 /* PORT3x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT4x */
+       -1, -1, -1, 46, 47, 48, 49, 50,                 /* PORT5x */
+       51, -1, -1, 54, 55, 56, 57, 58,                 /* PORT6x */
+       59, 60, 69, 70, 71, 72, 73, 74,                 /* PORT7x */
+       75, 76, 77, 78, 79, 80, 81, 82,                 /* PORT8x */
+       83, 84, 85, 86, 87, 88, 89, 90,                 /* PORT9x */
+       91, 92, 93, 94, 95, 96, 97, 98,                 /* PORT10x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT11x */
+       99, 100, 101, 102, 103, 104, 105, 106,          /* PORT12x */
+       107, 108, 109, 110, 111, 112, 113, 114,         /* PORT13x */
+       115, 116, 117, 118, 119, 120, 121, 122,         /* PORT14x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT15x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT16x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT17x */
+       61, 62, 63, 64, 65, 66, 67, 68,                 /* PORT18x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT19x */
+       123, 124, 125, 126, 127, 128, 129, 130,         /* PORT20x */
+       131, 132, 133, 134, 135, 136, 137, 138,         /* PORT21x */
+       139, 140, 141, 142, -1, -1, -1, -1,             /* PORT22x */
+       147, 148, 149, 150, 151, 152, 153, 154,         /* PORT23x */
+       155, 156, 157, 143, 144, 145, 146, 158,         /* PORT24x */
+};
+static const int port_range_muxvals[] = {
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT0x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT1x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT2x */
+       15, 15, 15, -1, -1, -1, -1, -1,                 /* PORT3x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT4x */
+       -1, -1, -1, 15, 15, 15, 15, 15,                 /* PORT5x */
+       15, -1, -1, 15, 15, 15, 15, 15,                 /* PORT6x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT7x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT8x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT9x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT10x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT11x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT12x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT13x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT14x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT15x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT16x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT17x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT18x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT19x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT20x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT21x */
+       15, 15, 15, 15, -1, -1, -1, -1,                 /* PORT22x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT23x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT24x */
+};
+static const unsigned xirq_pins[] = {
+       149, 150, 151, 152, 153, 154, 155, 156,         /* XIRQ0-7 */
+       157, 143, 144, 145, 85, 146, 158, 84,           /* XIRQ8-15 */
+       141, 142, 148, 50, 51, 159, 160, 161,           /* XIRQ16-23 */
+};
+static const int xirq_muxvals[] = {
+       14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ0-7 */
+       14, 14, 14, 14, 13, 14, 14, 13,                 /* XIRQ8-15 */
+       14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ16-23 */
+};
+static const unsigned xirq_alternatives_pins[] = {
+       94, 95, 96, 97, 98, 99, 100, 101,               /* XIRQ0-7 */
+       102, 103, 104, 105, 106, 107,                   /* XIRQ8-11,13,14 */
+       108, 109, 110, 111, 112, 113, 114, 115,         /* XIRQ16-23 */
+       9, 10, 11, 12, 13, 14, 15, 16,                  /* XIRQ4-11 */
+       17, 0, 1, 2, 3, 4, 5, 6, 7, 8,                  /* XIRQ13,14,16-23 */
+       139, 140, 135, 147,                             /* XIRQ17,18,21,22 */
+};
+static const int xirq_alternatives_muxvals[] = {
+       14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ0-7 */
+       14, 14, 14, 14, 14, 14,                         /* XIRQ8-11,13,14 */
+       14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ16-23 */
+       14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ4-11 */
+       14, 14, 14, 14, 14, 14, 14, 14, 14, 14,         /* XIRQ13,14,16-23 */
+       14, 14, 14, 14,                                 /* XIRQ17,18,21,22 */
+};
+
+static const struct uniphier_pinctrl_group uniphier_ld11_groups[] = {
+       UNIPHIER_PINCTRL_GROUP(emmc),
+       UNIPHIER_PINCTRL_GROUP(emmc_dat8),
+       UNIPHIER_PINCTRL_GROUP(ether_rmii),
+       UNIPHIER_PINCTRL_GROUP(i2c0),
+       UNIPHIER_PINCTRL_GROUP(i2c1),
+       UNIPHIER_PINCTRL_GROUP(i2c3),
+       UNIPHIER_PINCTRL_GROUP(i2c4),
+       UNIPHIER_PINCTRL_GROUP(nand),
+       UNIPHIER_PINCTRL_GROUP(system_bus),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs1),
+       UNIPHIER_PINCTRL_GROUP(uart0),
+       UNIPHIER_PINCTRL_GROUP(uart1),
+       UNIPHIER_PINCTRL_GROUP(uart2),
+       UNIPHIER_PINCTRL_GROUP(uart3),
+       UNIPHIER_PINCTRL_GROUP(usb0),
+       UNIPHIER_PINCTRL_GROUP(usb1),
+       UNIPHIER_PINCTRL_GROUP(usb2),
+       UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range),
+       UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq),
+       UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq_alternatives),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range, 0),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range, 1),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range, 2),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range, 3),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range, 4),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range, 5),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range, 6),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range, 7),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range, 8),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range, 9),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range, 10),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range, 11),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range, 12),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range, 13),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range, 14),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range, 15),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range, 16),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range, 17),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range, 18),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range, 19),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range, 20),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range, 21),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range, 22),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range, 23),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range, 24),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range, 25),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range, 26),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range, 43),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range, 44),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range, 45),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range, 46),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range, 47),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range, 48),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range, 51),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range, 52),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range, 53),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range, 54),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range, 55),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range, 56),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range, 57),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range, 58),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range, 59),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range, 60),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range, 61),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range, 62),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range, 63),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range, 64),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range, 65),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range, 66),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range, 67),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range, 68),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range, 69),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range, 70),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range, 71),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range, 72),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range, 73),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range, 74),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range, 75),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range, 76),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range, 77),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range, 78),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range, 79),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range, 80),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range, 81),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range, 82),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range, 83),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range, 84),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range, 85),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range, 86),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range, 87),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range, 96),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range, 97),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range, 98),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range, 99),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range, 100),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range, 101),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range, 102),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range, 103),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range, 104),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range, 105),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range, 106),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range, 107),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range, 108),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range, 109),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range, 110),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range, 111),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range, 112),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range, 113),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range, 114),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range, 115),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range, 116),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range, 117),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range, 118),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range, 119),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port180, port_range, 144),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port181, port_range, 145),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port182, port_range, 146),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port183, port_range, 147),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port184, port_range, 148),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port185, port_range, 149),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port186, port_range, 150),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port187, port_range, 151),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port200, port_range, 160),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port201, port_range, 161),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port202, port_range, 162),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port203, port_range, 163),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port204, port_range, 164),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port205, port_range, 165),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port206, port_range, 166),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port207, port_range, 167),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port210, port_range, 168),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port211, port_range, 169),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port212, port_range, 170),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port213, port_range, 171),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port214, port_range, 172),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port215, port_range, 173),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port216, port_range, 174),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port217, port_range, 175),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port220, port_range, 176),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port221, port_range, 177),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port222, port_range, 178),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port223, port_range, 179),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port230, port_range, 184),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port231, port_range, 185),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port232, port_range, 186),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port233, port_range, 187),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port234, port_range, 188),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port235, port_range, 189),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port236, port_range, 190),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port237, port_range, 191),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port240, port_range, 192),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port241, port_range, 193),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port242, port_range, 194),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port243, port_range, 195),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port244, port_range, 196),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port245, port_range, 197),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port246, port_range, 198),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port247, port_range, 199),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0, xirq, 0),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1, xirq, 1),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2, xirq, 2),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3, xirq, 3),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4, xirq, 4),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5, xirq, 5),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6, xirq, 6),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7, xirq, 7),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8, xirq, 8),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9, xirq, 9),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10, xirq, 10),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11, xirq, 11),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq12, xirq, 12),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq13, xirq, 13),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14, xirq, 14),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq15, xirq, 15),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq16, xirq, 16),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17, xirq, 17),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18, xirq, 18),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq19, xirq, 19),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq20, xirq, 20),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq21, xirq, 21),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq22, xirq, 22),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq23, xirq, 23),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0b, xirq_alternatives, 0),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1b, xirq_alternatives, 1),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2b, xirq_alternatives, 2),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3b, xirq_alternatives, 3),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4b, xirq_alternatives, 4),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5b, xirq_alternatives, 5),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6b, xirq_alternatives, 6),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7b, xirq_alternatives, 7),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8b, xirq_alternatives, 8),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9b, xirq_alternatives, 9),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10b, xirq_alternatives, 10),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11b, xirq_alternatives, 11),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq13b, xirq_alternatives, 12),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14b, xirq_alternatives, 13),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq16b, xirq_alternatives, 14),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17b, xirq_alternatives, 15),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18b, xirq_alternatives, 16),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq19b, xirq_alternatives, 17),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq20b, xirq_alternatives, 18),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq21b, xirq_alternatives, 19),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq22b, xirq_alternatives, 20),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq23b, xirq_alternatives, 21),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4c, xirq_alternatives, 22),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5c, xirq_alternatives, 23),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6c, xirq_alternatives, 24),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7c, xirq_alternatives, 25),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8c, xirq_alternatives, 26),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9c, xirq_alternatives, 27),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10c, xirq_alternatives, 28),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11c, xirq_alternatives, 29),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq13c, xirq_alternatives, 30),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14c, xirq_alternatives, 31),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq16c, xirq_alternatives, 32),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17c, xirq_alternatives, 33),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18c, xirq_alternatives, 34),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq19c, xirq_alternatives, 35),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq20c, xirq_alternatives, 36),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq21c, xirq_alternatives, 37),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq22c, xirq_alternatives, 38),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq23c, xirq_alternatives, 39),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17d, xirq_alternatives, 40),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18d, xirq_alternatives, 41),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq21d, xirq_alternatives, 42),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq22d, xirq_alternatives, 43),
+};
+
+static const char * const emmc_groups[] = {"emmc", "emmc_dat8"};
+static const char * const ether_rmii_groups[] = {"ether_rmii"};
+static const char * const i2c0_groups[] = {"i2c0"};
+static const char * const i2c1_groups[] = {"i2c1"};
+static const char * const i2c3_groups[] = {"i2c3"};
+static const char * const i2c4_groups[] = {"i2c4"};
+static const char * const nand_groups[] = {"nand"};
+static const char * const system_bus_groups[] = {"system_bus",
+                                                "system_bus_cs1"};
+static const char * const uart0_groups[] = {"uart0"};
+static const char * const uart1_groups[] = {"uart1"};
+static const char * const uart2_groups[] = {"uart2"};
+static const char * const uart3_groups[] = {"uart3"};
+static const char * const usb0_groups[] = {"usb0"};
+static const char * const usb1_groups[] = {"usb1"};
+static const char * const usb2_groups[] = {"usb2"};
+static const char * const port_groups[] = {
+       "port00",  "port01",  "port02",  "port03",
+       "port04",  "port05",  "port06",  "port07",
+       "port10",  "port11",  "port12",  "port13",
+       "port14",  "port15",  "port16",  "port17",
+       "port20",  "port21",  "port22",  "port23",
+       "port24",  "port25",  "port26",  "port27",
+       "port30",  "port31",  "port32",
+       /* port33-52 missing */          "port53",
+       "port54",  "port55",  "port56",  "port57",
+       "port60", /* port61-62 missing*/ "port63",
+       "port64",  "port65",  "port66",  "port67",
+       "port70",  "port71",  "port72",  "port73",
+       "port74",  "port75",  "port76",  "port77",
+       "port80",  "port81",  "port82",  "port83",
+       "port84",  "port85",  "port86",  "port87",
+       "port90",  "port91",  "port92",  "port93",
+       "port94",  "port95",  "port96",  "port97",
+       "port100", "port101", "port102", "port103",
+       "port104", "port105", "port106", "port107",
+       /* port110-117 missing */
+       "port120", "port121", "port122", "port123",
+       "port124", "port125", "port126", "port127",
+       "port130", "port131", "port132", "port133",
+       "port134", "port135", "port136", "port137",
+       "port140", "port141", "port142", "port143",
+       "port144", "port145", "port146", "port147",
+       /* port150-177 missing */
+       "port180", "port181", "port182", "port183",
+       "port184", "port185", "port186", "port187",
+       /* port190-197 missing */
+       "port200", "port201", "port202", "port203",
+       "port204", "port205", "port206", "port207",
+       "port210", "port211", "port212", "port213",
+       "port214", "port215", "port216", "port217",
+       "port220", "port221", "port222", "port223",
+       /* port224-227 missing */
+       "port230", "port231", "port232", "port233",
+       "port234", "port235", "port236", "port237",
+       "port240", "port241", "port242", "port243",
+       "port244", "port245", "port246", "port247",
+};
+static const char * const xirq_groups[] = {
+       "xirq0",  "xirq1",  "xirq2",  "xirq3",
+       "xirq4",  "xirq5",  "xirq6",  "xirq7",
+       "xirq8",  "xirq9",  "xirq10", "xirq11",
+       "xirq12", "xirq13", "xirq14", "xirq15",
+       "xirq16", "xirq17", "xirq18", "xirq19",
+       "xirq20", "xirq21", "xirq22", "xirq23",
+       "xirq0b",  "xirq1b",  "xirq2b",  "xirq3b",
+       "xirq4b",  "xirq5b",  "xirq6b",  "xirq7b",
+       "xirq8b",  "xirq9b",  "xirq10b", "xirq11b",
+       /* none */ "xirq13b", "xirq14b", /* none */
+       "xirq16b", "xirq17b", "xirq18b", "xirq19b",
+       "xirq20b", "xirq21b", "xirq22b", "xirq23b",
+       "xirq4c",  "xirq5c",  "xirq6c",  "xirq7c",
+       "xirq8c",  "xirq9c",  "xirq10c", "xirq11c",
+       /* none */ "xirq13c", "xirq14c", /* none */
+       "xirq16c", "xirq17c", "xirq18c", "xirq19c",
+       "xirq20c", "xirq21c", "xirq22c", "xirq23c",
+       "xirq17d", "xirq18d", "xirq21d", "xirq22d",
+};
+
+static const struct uniphier_pinmux_function uniphier_ld11_functions[] = {
+       UNIPHIER_PINMUX_FUNCTION(emmc),
+       UNIPHIER_PINMUX_FUNCTION(ether_rmii),
+       UNIPHIER_PINMUX_FUNCTION(i2c0),
+       UNIPHIER_PINMUX_FUNCTION(i2c1),
+       UNIPHIER_PINMUX_FUNCTION(i2c3),
+       UNIPHIER_PINMUX_FUNCTION(i2c4),
+       UNIPHIER_PINMUX_FUNCTION(nand),
+       UNIPHIER_PINMUX_FUNCTION(system_bus),
+       UNIPHIER_PINMUX_FUNCTION(uart0),
+       UNIPHIER_PINMUX_FUNCTION(uart1),
+       UNIPHIER_PINMUX_FUNCTION(uart2),
+       UNIPHIER_PINMUX_FUNCTION(uart3),
+       UNIPHIER_PINMUX_FUNCTION(usb0),
+       UNIPHIER_PINMUX_FUNCTION(usb1),
+       UNIPHIER_PINMUX_FUNCTION(usb2),
+       UNIPHIER_PINMUX_FUNCTION(port),
+       UNIPHIER_PINMUX_FUNCTION(xirq),
+};
+
+static struct uniphier_pinctrl_socdata uniphier_ld11_pindata = {
+       .pins = uniphier_ld11_pins,
+       .npins = ARRAY_SIZE(uniphier_ld11_pins),
+       .groups = uniphier_ld11_groups,
+       .groups_count = ARRAY_SIZE(uniphier_ld11_groups),
+       .functions = uniphier_ld11_functions,
+       .functions_count = ARRAY_SIZE(uniphier_ld11_functions),
+       .caps = UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL,
+};
+
+static int uniphier_ld11_pinctrl_probe(struct platform_device *pdev)
+{
+       return uniphier_pinctrl_probe(pdev, &uniphier_ld11_pindata);
+}
+
+static const struct of_device_id uniphier_ld11_pinctrl_match[] = {
+       { .compatible = "socionext,uniphier-ld11-pinctrl" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_ld11_pinctrl_match);
+
+static struct platform_driver uniphier_ld11_pinctrl_driver = {
+       .probe = uniphier_ld11_pinctrl_probe,
+       .driver = {
+               .name = "uniphier-ld11-pinctrl",
+               .of_match_table = uniphier_ld11_pinctrl_match,
+       },
+};
+module_platform_driver(uniphier_ld11_pinctrl_driver);
+
+MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier PH1-LD11 pinctrl driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c
new file mode 100644 (file)
index 0000000..aa8bd97
--- /dev/null
@@ -0,0 +1,1050 @@
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-uniphier.h"
+
+static const struct pinctrl_pin_desc uniphier_ld20_pins[] = {
+       UNIPHIER_PINCTRL_PIN(0, "XECS1", 0,
+                            0, UNIPHIER_PIN_DRV_3BIT,
+                            0, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(1, "ERXW", 1,
+                            1, UNIPHIER_PIN_DRV_3BIT,
+                            1, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(2, "XERWE1", 2,
+                            2, UNIPHIER_PIN_DRV_3BIT,
+                            2, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(3, "XNFWP", 3,
+                            3, UNIPHIER_PIN_DRV_3BIT,
+                            3, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(4, "XNFCE0", 4,
+                            4, UNIPHIER_PIN_DRV_3BIT,
+                            4, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(5, "NFRYBY0", 5,
+                            5, UNIPHIER_PIN_DRV_3BIT,
+                            5, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(6, "XNFRE", 6,
+                            6, UNIPHIER_PIN_DRV_3BIT,
+                            6, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(7, "XNFWE", 7,
+                            7, UNIPHIER_PIN_DRV_3BIT,
+                            7, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(8, "NFALE", 8,
+                            8, UNIPHIER_PIN_DRV_3BIT,
+                            8, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(9, "NFCLE", 9,
+                            9, UNIPHIER_PIN_DRV_3BIT,
+                            9, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(10, "NFD0", 10,
+                            10, UNIPHIER_PIN_DRV_3BIT,
+                            10, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(11, "NFD1", 11,
+                            11, UNIPHIER_PIN_DRV_3BIT,
+                            11, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(12, "NFD2", 12,
+                            12, UNIPHIER_PIN_DRV_3BIT,
+                            12, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(13, "NFD3", 13,
+                            13, UNIPHIER_PIN_DRV_3BIT,
+                            13, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(14, "NFD4", 14,
+                            14, UNIPHIER_PIN_DRV_3BIT,
+                            14, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(15, "NFD5", 15,
+                            15, UNIPHIER_PIN_DRV_3BIT,
+                            15, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(16, "NFD6", 16,
+                            16, UNIPHIER_PIN_DRV_3BIT,
+                            16, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(17, "NFD7", 17,
+                            17, UNIPHIER_PIN_DRV_3BIT,
+                            17, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(18, "XERST", 18,
+                            0, UNIPHIER_PIN_DRV_2BIT,
+                            18, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(19, "MMCCLK", 19,
+                            1, UNIPHIER_PIN_DRV_2BIT,
+                            19, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(20, "MMCCMD", 20,
+                            2, UNIPHIER_PIN_DRV_2BIT,
+                            20, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(21, "MMCDS", 21,
+                            3, UNIPHIER_PIN_DRV_2BIT,
+                            21, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(22, "MMCDAT0", 22,
+                            4, UNIPHIER_PIN_DRV_2BIT,
+                            22, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(23, "MMCDAT1", 23,
+                            5, UNIPHIER_PIN_DRV_2BIT,
+                            23, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(24, "MMCDAT2", 24,
+                            6, UNIPHIER_PIN_DRV_2BIT,
+                            24, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(25, "MMCDAT3", 25,
+                            7, UNIPHIER_PIN_DRV_2BIT,
+                            25, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(26, "MMCDAT4", 26,
+                            8, UNIPHIER_PIN_DRV_2BIT,
+                            26, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(27, "MMCDAT5", 27,
+                            9, UNIPHIER_PIN_DRV_2BIT,
+                            27, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(28, "MMCDAT6", 28,
+                            10, UNIPHIER_PIN_DRV_2BIT,
+                            28, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(29, "MMCDAT7", 29,
+                            11, UNIPHIER_PIN_DRV_2BIT,
+                            29, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(30, "MDC", 30,
+                            18, UNIPHIER_PIN_DRV_3BIT,
+                            30, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(31, "MDIO", 31,
+                            19, UNIPHIER_PIN_DRV_3BIT,
+                            31, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(32, "MDIO_INTL", 32,
+                            20, UNIPHIER_PIN_DRV_3BIT,
+                            32, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(33, "PHYRSTL", 33,
+                            21, UNIPHIER_PIN_DRV_3BIT,
+                            33, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(34, "RGMII_RXCLK", 34,
+                            22, UNIPHIER_PIN_DRV_3BIT,
+                            34, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(35, "RGMII_RXD0", 35,
+                            23, UNIPHIER_PIN_DRV_3BIT,
+                            35, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(36, "RGMII_RXD1", 36,
+                            24, UNIPHIER_PIN_DRV_3BIT,
+                            36, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(37, "RGMII_RXD2", 37,
+                            25, UNIPHIER_PIN_DRV_3BIT,
+                            37, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(38, "RGMII_RXD3", 38,
+                            26, UNIPHIER_PIN_DRV_3BIT,
+                            38, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(39, "RGMII_RXCTL", 39,
+                            27, UNIPHIER_PIN_DRV_3BIT,
+                            39, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(40, "RGMII_TXCLK", 40,
+                            28, UNIPHIER_PIN_DRV_3BIT,
+                            40, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(41, "RGMII_TXD0", 41,
+                            29, UNIPHIER_PIN_DRV_3BIT,
+                            41, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(42, "RGMII_TXD1", 42,
+                            30, UNIPHIER_PIN_DRV_3BIT,
+                            42, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(43, "RGMII_TXD2", 43,
+                            31, UNIPHIER_PIN_DRV_3BIT,
+                            43, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(44, "RGMII_TXD3", 44,
+                            32, UNIPHIER_PIN_DRV_3BIT,
+                            44, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(45, "RGMII_TXCTL", 45,
+                            33, UNIPHIER_PIN_DRV_3BIT,
+                            45, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(46, "USB0VBUS", 46,
+                            34, UNIPHIER_PIN_DRV_3BIT,
+                            46, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(47, "USB0OD", 47,
+                            35, UNIPHIER_PIN_DRV_3BIT,
+                            47, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(48, "USB1VBUS", 48,
+                            36, UNIPHIER_PIN_DRV_3BIT,
+                            48, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(49, "USB1OD", 49,
+                            37, UNIPHIER_PIN_DRV_3BIT,
+                            49, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(50, "USB2VBUS", 50,
+                            38, UNIPHIER_PIN_DRV_3BIT,
+                            50, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(51, "USB2OD", 51,
+                            39, UNIPHIER_PIN_DRV_3BIT,
+                            51, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(52, "USB3VBUS", 52,
+                            40, UNIPHIER_PIN_DRV_3BIT,
+                            52, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(53, "USB3OD", 53,
+                            41, UNIPHIER_PIN_DRV_3BIT,
+                            53, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(54, "TXD0", 54,
+                            42, UNIPHIER_PIN_DRV_3BIT,
+                            54, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(55, "RXD0", 55,
+                            43, UNIPHIER_PIN_DRV_3BIT,
+                            55, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(56, "SPISYNC0", 56,
+                            44, UNIPHIER_PIN_DRV_3BIT,
+                            56, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(57, "SPISCLK0", 57,
+                            45, UNIPHIER_PIN_DRV_3BIT,
+                            57, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(58, "SPITXD0", 58,
+                            46, UNIPHIER_PIN_DRV_3BIT,
+                            58, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(59, "SPIRXD0", 59,
+                            47, UNIPHIER_PIN_DRV_3BIT,
+                            59, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(60, "AGCI", 60,
+                            48, UNIPHIER_PIN_DRV_3BIT,
+                            60, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(61, "DMDSDA0", 61,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(62, "DMDSCL0", 62,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(63, "SDA0", 63,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(64, "SCL0", 64,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(65, "SDA1", 65,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(66, "SCL1", 66,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(67, "HIN", 67,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(68, "VIN", 68,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
+                            -1, UNIPHIER_PIN_PULL_NONE),
+       UNIPHIER_PINCTRL_PIN(69, "PCA00", 69,
+                            49, UNIPHIER_PIN_DRV_3BIT,
+                            69, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(70, "PCA01", 70,
+                            50, UNIPHIER_PIN_DRV_3BIT,
+                            70, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(71, "PCA02", 71,
+                            51, UNIPHIER_PIN_DRV_3BIT,
+                            71, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(72, "PCA03", 72,
+                            52, UNIPHIER_PIN_DRV_3BIT,
+                            72, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(73, "PCA04", 73,
+                            53, UNIPHIER_PIN_DRV_3BIT,
+                            73, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(74, "PCA05", 74,
+                            54, UNIPHIER_PIN_DRV_3BIT,
+                            74, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(75, "PCA06", 75,
+                            55, UNIPHIER_PIN_DRV_3BIT,
+                            75, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(76, "PCA07", 76,
+                            56, UNIPHIER_PIN_DRV_3BIT,
+                            76, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(77, "PCA08", 77,
+                            57, UNIPHIER_PIN_DRV_3BIT,
+                            77, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(78, "PCA09", 78,
+                            58, UNIPHIER_PIN_DRV_3BIT,
+                            78, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(79, "PCA10", 79,
+                            59, UNIPHIER_PIN_DRV_3BIT,
+                            79, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(80, "PCA11", 80,
+                            60, UNIPHIER_PIN_DRV_3BIT,
+                            80, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(81, "PCA12", 81,
+                            61, UNIPHIER_PIN_DRV_3BIT,
+                            81, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(82, "PCA13", 82,
+                            62, UNIPHIER_PIN_DRV_3BIT,
+                            82, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(83, "PCA14", 83,
+                            63, UNIPHIER_PIN_DRV_3BIT,
+                            83, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(84, "PC0READY", 84,
+                            0, UNIPHIER_PIN_DRV_1BIT,
+                            84, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(85, "PC0CD1", 85,
+                            1, UNIPHIER_PIN_DRV_1BIT,
+                            85, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(86, "PC0CD2", 86,
+                            2, UNIPHIER_PIN_DRV_1BIT,
+                            86, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(87, "PC0WAIT", 87,
+                            3, UNIPHIER_PIN_DRV_1BIT,
+                            87, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(88, "PC0RESET", 88,
+                            4, UNIPHIER_PIN_DRV_1BIT,
+                            88, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(89, "PC0CE1", 89,
+                            5, UNIPHIER_PIN_DRV_1BIT,
+                            89, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(90, "PC0WE", 90,
+                            6, UNIPHIER_PIN_DRV_1BIT,
+                            90, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(91, "PC0OE", 91,
+                            7, UNIPHIER_PIN_DRV_1BIT,
+                            91, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(92, "PC0IOWR", 92,
+                            8, UNIPHIER_PIN_DRV_1BIT,
+                            92, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(93, "PC0IORD", 93,
+                            9, UNIPHIER_PIN_DRV_1BIT,
+                            93, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(94, "PCD00", 94,
+                            10, UNIPHIER_PIN_DRV_1BIT,
+                            94, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(95, "PCD01", 95,
+                            11, UNIPHIER_PIN_DRV_1BIT,
+                            95, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(96, "PCD02", 96,
+                            12, UNIPHIER_PIN_DRV_1BIT,
+                            96, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(97, "PCD03", 97,
+                            13, UNIPHIER_PIN_DRV_1BIT,
+                            97, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(98, "PCD04", 98,
+                            14, UNIPHIER_PIN_DRV_1BIT,
+                            98, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(99, "PCD05", 99,
+                            15, UNIPHIER_PIN_DRV_1BIT,
+                            99, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(100, "PCD06", 100,
+                            16, UNIPHIER_PIN_DRV_1BIT,
+                            100, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(101, "PCD07", 101,
+                            17, UNIPHIER_PIN_DRV_1BIT,
+                            101, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(102, "HS0BCLKIN", 102,
+                            18, UNIPHIER_PIN_DRV_1BIT,
+                            102, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(103, "HS0SYNCIN", 103,
+                            19, UNIPHIER_PIN_DRV_1BIT,
+                            103, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(104, "HS0VALIN", 104,
+                            20, UNIPHIER_PIN_DRV_1BIT,
+                            104, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(105, "HS0DIN0", 105,
+                            21, UNIPHIER_PIN_DRV_1BIT,
+                            105, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(106, "HS0DIN1", 106,
+                            22, UNIPHIER_PIN_DRV_1BIT,
+                            106, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(107, "HS0DIN2", 107,
+                            23, UNIPHIER_PIN_DRV_1BIT,
+                            107, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(108, "HS0DIN3", 108,
+                            24, UNIPHIER_PIN_DRV_1BIT,
+                            108, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(109, "HS0DIN4", 109,
+                            25, UNIPHIER_PIN_DRV_1BIT,
+                            109, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(110, "HS0DIN5", 110,
+                            26, UNIPHIER_PIN_DRV_1BIT,
+                            110, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(111, "HS0DIN6", 111,
+                            27, UNIPHIER_PIN_DRV_1BIT,
+                            111, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(112, "HS0DIN7", 112,
+                            28, UNIPHIER_PIN_DRV_1BIT,
+                            112, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(113, "HS0BCLKOUT", 113,
+                            64, UNIPHIER_PIN_DRV_3BIT,
+                            113, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(114, "HS0SYNCOUT", 114,
+                            65, UNIPHIER_PIN_DRV_3BIT,
+                            114, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(115, "HS0VALOUT", 115,
+                            66, UNIPHIER_PIN_DRV_3BIT,
+                            115, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(116, "HS0DOUT0", 116,
+                            67, UNIPHIER_PIN_DRV_3BIT,
+                            116, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(117, "HS0DOUT1", 117,
+                            68, UNIPHIER_PIN_DRV_3BIT,
+                            117, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(118, "HS0DOUT2", 118,
+                            69, UNIPHIER_PIN_DRV_3BIT,
+                            118, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(119, "HS0DOUT3", 119,
+                            70, UNIPHIER_PIN_DRV_3BIT,
+                            119, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(120, "HS0DOUT4", 120,
+                            71, UNIPHIER_PIN_DRV_3BIT,
+                            120, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(121, "HS0DOUT5", 121,
+                            72, UNIPHIER_PIN_DRV_3BIT,
+                            121, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(122, "HS0DOUT6", 122,
+                            73, UNIPHIER_PIN_DRV_3BIT,
+                            122, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(123, "HS0DOUT7", 123,
+                            74, UNIPHIER_PIN_DRV_3BIT,
+                            123, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(124, "HS1BCLKIN", 124,
+                            75, UNIPHIER_PIN_DRV_3BIT,
+                            124, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(125, "HS1SYNCIN", 125,
+                            76, UNIPHIER_PIN_DRV_3BIT,
+                            125, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(126, "HS1VALIN", 126,
+                            77, UNIPHIER_PIN_DRV_3BIT,
+                            126, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(127, "HS1DIN0", 127,
+                            78, UNIPHIER_PIN_DRV_3BIT,
+                            127, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(128, "HS1DIN1", 128,
+                            79, UNIPHIER_PIN_DRV_3BIT,
+                            128, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(129, "HS1DIN2", 129,
+                            80, UNIPHIER_PIN_DRV_3BIT,
+                            129, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(130, "HS1DIN3", 130,
+                            81, UNIPHIER_PIN_DRV_3BIT,
+                            130, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(131, "HS1DIN4", 131,
+                            82, UNIPHIER_PIN_DRV_3BIT,
+                            131, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(132, "HS1DIN5", 132,
+                            83, UNIPHIER_PIN_DRV_3BIT,
+                            132, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(133, "HS1DIN6", 133,
+                            84, UNIPHIER_PIN_DRV_3BIT,
+                            133, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(134, "HS1DIN7", 134,
+                            85, UNIPHIER_PIN_DRV_3BIT,
+                            134, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(135, "AO1IEC", 135,
+                            86, UNIPHIER_PIN_DRV_3BIT,
+                            135, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(136, "AO1ARC", 136,
+                            87, UNIPHIER_PIN_DRV_3BIT,
+                            136, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(137, "AO1DACCK", 137,
+                            88, UNIPHIER_PIN_DRV_3BIT,
+                            137, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(138, "AO1BCK", 138,
+                            89, UNIPHIER_PIN_DRV_3BIT,
+                            138, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(139, "AO1LRCK", 139,
+                            90, UNIPHIER_PIN_DRV_3BIT,
+                            139, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(140, "AO1D0", 140,
+                            91, UNIPHIER_PIN_DRV_3BIT,
+                            140, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(141, "AO1D1", 141,
+                            92, UNIPHIER_PIN_DRV_3BIT,
+                            141, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(142, "AO1D2", 142,
+                            93, UNIPHIER_PIN_DRV_3BIT,
+                            142, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(143, "HTPDN0", 143,
+                            94, UNIPHIER_PIN_DRV_3BIT,
+                            143, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(144, "LOCKN0", 144,
+                            95, UNIPHIER_PIN_DRV_3BIT,
+                            144, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(145, "HTPDN1", 145,
+                            96, UNIPHIER_PIN_DRV_3BIT,
+                            145, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(146, "LOCKN1", 146,
+                            97, UNIPHIER_PIN_DRV_3BIT,
+                            146, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(147, "PWMA", 147,
+                            98, UNIPHIER_PIN_DRV_3BIT,
+                            147, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(148, "LR_GOUT", 148,
+                            99, UNIPHIER_PIN_DRV_3BIT,
+                            148, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(149, "XIRQ0", 149,
+                            100, UNIPHIER_PIN_DRV_3BIT,
+                            149, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(150, "XIRQ1", 150,
+                            101, UNIPHIER_PIN_DRV_3BIT,
+                            150, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(151, "XIRQ2", 151,
+                            102, UNIPHIER_PIN_DRV_3BIT,
+                            151, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(152, "XIRQ3", 152,
+                            103, UNIPHIER_PIN_DRV_3BIT,
+                            152, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(153, "XIRQ4", 153,
+                            104, UNIPHIER_PIN_DRV_3BIT,
+                            153, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(154, "XIRQ5", 154,
+                            105, UNIPHIER_PIN_DRV_3BIT,
+                            154, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(155, "XIRQ6", 155,
+                            106, UNIPHIER_PIN_DRV_3BIT,
+                            155, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(156, "XIRQ7", 156,
+                            107, UNIPHIER_PIN_DRV_3BIT,
+                            156, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(157, "XIRQ8", 157,
+                            108, UNIPHIER_PIN_DRV_3BIT,
+                            157, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(158, "XIRQ9", 158,
+                            109, UNIPHIER_PIN_DRV_3BIT,
+                            158, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(159, "XIRQ10", 159,
+                            110, UNIPHIER_PIN_DRV_3BIT,
+                            159, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(160, "XIRQ11", 160,
+                            111, UNIPHIER_PIN_DRV_3BIT,
+                            160, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(161, "XIRQ13", 161,
+                            112, UNIPHIER_PIN_DRV_3BIT,
+                            161, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(162, "XIRQ14", 162,
+                            113, UNIPHIER_PIN_DRV_3BIT,
+                            162, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(163, "XIRQ16", 163,
+                            114, UNIPHIER_PIN_DRV_3BIT,
+                            163, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(164, "XIRQ17", 164,
+                            115, UNIPHIER_PIN_DRV_3BIT,
+                            164, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(165, "XIRQ18", 165,
+                            116, UNIPHIER_PIN_DRV_3BIT,
+                            165, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(166, "XIRQ19", 166,
+                            117, UNIPHIER_PIN_DRV_3BIT,
+                            166, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(167, "XIRQ20", 167,
+                            118, UNIPHIER_PIN_DRV_3BIT,
+                            167, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(168, "PORT00", 168,
+                            119, UNIPHIER_PIN_DRV_3BIT,
+                            168, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(169, "PORT01", 169,
+                            120, UNIPHIER_PIN_DRV_3BIT,
+                            169, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(170, "PORT02", 170,
+                            121, UNIPHIER_PIN_DRV_3BIT,
+                            170, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(171, "PORT03", 171,
+                            122, UNIPHIER_PIN_DRV_3BIT,
+                            171, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(172, "PORT04", 172,
+                            123, UNIPHIER_PIN_DRV_3BIT,
+                            172, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(173, "CK27FO", 173,
+                            124, UNIPHIER_PIN_DRV_3BIT,
+                            173, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(174, "PHSYNCO", 174,
+                            125, UNIPHIER_PIN_DRV_3BIT,
+                            174, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(175, "PVSYNCO", 175,
+                            126, UNIPHIER_PIN_DRV_3BIT,
+                            175, UNIPHIER_PIN_PULL_DOWN),
+};
+
+static const unsigned emmc_pins[] = {18, 19, 20, 21, 22, 23, 24, 25};
+static const int emmc_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned emmc_dat8_pins[] = {26, 27, 28, 29};
+static const int emmc_dat8_muxvals[] = {0, 0, 0, 0};
+static const unsigned ether_rgmii_pins[] = {30, 31, 32, 33, 34, 35, 36, 37, 38,
+                                           39, 40, 41, 42, 43, 44, 45};
+static const int ether_rgmii_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                         0, 0, 0, 0};
+static const unsigned ether_rmii_pins[] = {30, 31, 32, 33, 34, 35, 36, 37, 39,
+                                          41, 42, 45};
+static const int ether_rmii_muxvals[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
+static const unsigned i2c0_pins[] = {63, 64};
+static const int i2c0_muxvals[] = {0, 0};
+static const unsigned i2c1_pins[] = {65, 66};
+static const int i2c1_muxvals[] = {0, 0};
+static const unsigned i2c3_pins[] = {67, 68};
+static const int i2c3_muxvals[] = {1, 1};
+static const unsigned i2c4_pins[] = {61, 62};
+static const int i2c4_muxvals[] = {1, 1};
+static const unsigned nand_pins[] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+                                    15, 16, 17};
+static const int nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned sd_pins[] = {10, 11, 12, 13, 14, 15, 16, 17};
+static const int sd_muxvals[] = {3, 3, 3, 3, 3, 3, 3, 3};  /* No SDVOLC */
+static const unsigned system_bus_pins[] = {1, 2, 6, 7, 8, 9, 10, 11, 12, 13,
+                                          14, 15, 16, 17};
+static const int system_bus_muxvals[] = {0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+                                        2};
+static const unsigned system_bus_cs1_pins[] = {0};
+static const int system_bus_cs1_muxvals[] = {0};
+static const unsigned uart0_pins[] = {54, 55};
+static const int uart0_muxvals[] = {0, 0};
+static const unsigned uart1_pins[] = {58, 59};
+static const int uart1_muxvals[] = {1, 1};
+static const unsigned uart2_pins[] = {90, 91};
+static const int uart2_muxvals[] = {1, 1};
+static const unsigned uart3_pins[] = {94, 95};
+static const int uart3_muxvals[] = {1, 1};
+static const unsigned usb0_pins[] = {46, 47};
+static const int usb0_muxvals[] = {0, 0};
+static const unsigned usb1_pins[] = {48, 49};
+static const int usb1_muxvals[] = {0, 0};
+static const unsigned usb2_pins[] = {50, 51};
+static const int usb2_muxvals[] = {0, 0};
+static const unsigned usb3_pins[] = {52, 53};
+static const int usb3_muxvals[] = {0, 0};
+static const unsigned port_range_pins[] = {
+       168, 169, 170, 171, 172, 173, 174, 175,         /* PORT0x */
+       0, 1, 2, 3, 4, 5, 6, 7,                         /* PORT1x */
+       8, 9, 10, 11, 12, 13, 14, 15,                   /* PORT2x */
+       16, 17, 18, 30, 31, 32, 33, 34,                 /* PORT3x */
+       35, 36, 37, 38, 39, 40, 41, 42,                 /* PORT4x */
+       43, 44, 45, 46, 47, 48, 49, 50,                 /* PORT5x */
+       51, 52, 53, 54, 55, 56, 57, 58,                 /* PORT6x */
+       59, 60, 69, 70, 71, 72, 73, 74,                 /* PORT7x */
+       75, 76, 77, 78, 79, 80, 81, 82,                 /* PORT8x */
+       83, 84, 85, 86, 87, 88, 89, 90,                 /* PORT9x */
+       91, 92, 93, 94, 95, 96, 97, 98,                 /* PORT10x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT11x */
+       99, 100, 101, 102, 103, 104, 105, 106,          /* PORT12x */
+       107, 108, 109, 110, 111, 112, 113, 114,         /* PORT13x */
+       115, 116, 117, 118, 119, 120, 121, 122,         /* PORT14x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT15x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT16x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT17x */
+       61, 62, 63, 64, 65, 66, 67, 68,                 /* PORT18x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT19x */
+       123, 124, 125, 126, 127, 128, 129, 130,         /* PORT20x */
+       131, 132, 133, 134, 135, 136, 137, 138,         /* PORT21x */
+       139, 140, 141, 142, 143, 144, 145, 146,         /* PORT22x */
+       147, 148, 149, 150, 151, 152, 153, 154,         /* PORT23x */
+       155, 156, 157, 158, 159, 160, 161, 162,         /* PORT24x */
+       163, 164, 165, 166, 167,                        /* PORT25x */
+};
+static const int port_range_muxvals[] = {
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT0x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT1x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT2x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT3x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT4x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT5x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT6x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT7x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT8x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT9x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT10x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT11x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT12x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT13x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT14x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT15x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT16x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT17x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT18x */
+       -1, -1, -1, -1, -1, -1, -1, -1,                 /* PORT19x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT20x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT21x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT22x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT23x */
+       15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT24x */
+       15, 15, 15, 15, 15,                             /* PORT25x */
+};
+static const unsigned xirq_pins[] = {
+       149, 150, 151, 152, 153, 154, 155, 156,         /* XIRQ0-7 */
+       157, 158, 159, 160, 85, 161, 162, 84,           /* XIRQ8-15 */
+       163, 164, 165, 166, 167, 146, 52, 53,           /* XIRQ16-23 */
+};
+static const int xirq_muxvals[] = {
+       14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ0-7 */
+       14, 14, 14, 14, 13, 14, 14, 13,                 /* XIRQ8-15 */
+       14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ16-23 */
+};
+static const unsigned xirq_alternatives_pins[] = {
+       94, 95, 96, 97, 98, 99, 100, 101,               /* XIRQ0-7 */
+       102, 103, 104, 105, 106, 107,                   /* XIRQ8-11,13,14 */
+       108, 109, 110, 111, 112, 147, 141, 142,         /* XIRQ16-23 */
+};
+static const int xirq_alternatives_muxvals[] = {
+       14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ0-7 */
+       14, 14, 14, 14, 14, 14,                         /* XIRQ8-11,13,14 */
+       14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ16-23 */
+};
+
+static const struct uniphier_pinctrl_group uniphier_ld20_groups[] = {
+       UNIPHIER_PINCTRL_GROUP(emmc),
+       UNIPHIER_PINCTRL_GROUP(emmc_dat8),
+       UNIPHIER_PINCTRL_GROUP(ether_rgmii),
+       UNIPHIER_PINCTRL_GROUP(ether_rmii),
+       UNIPHIER_PINCTRL_GROUP(i2c0),
+       UNIPHIER_PINCTRL_GROUP(i2c1),
+       UNIPHIER_PINCTRL_GROUP(i2c3),
+       UNIPHIER_PINCTRL_GROUP(i2c4),
+       UNIPHIER_PINCTRL_GROUP(nand),
+       UNIPHIER_PINCTRL_GROUP(sd),
+       UNIPHIER_PINCTRL_GROUP(system_bus),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs1),
+       UNIPHIER_PINCTRL_GROUP(uart0),
+       UNIPHIER_PINCTRL_GROUP(uart1),
+       UNIPHIER_PINCTRL_GROUP(uart2),
+       UNIPHIER_PINCTRL_GROUP(uart3),
+       UNIPHIER_PINCTRL_GROUP(usb0),
+       UNIPHIER_PINCTRL_GROUP(usb1),
+       UNIPHIER_PINCTRL_GROUP(usb2),
+       UNIPHIER_PINCTRL_GROUP(usb3),
+       UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range),
+       UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq),
+       UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq_alternatives),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range, 0),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range, 1),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range, 2),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range, 3),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range, 4),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range, 5),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range, 6),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range, 7),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range, 8),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range, 9),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range, 10),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range, 11),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range, 12),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range, 13),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range, 14),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range, 15),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range, 16),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range, 17),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range, 18),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range, 19),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range, 20),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range, 21),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range, 22),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range, 23),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range, 24),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range, 25),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range, 26),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port33, port_range, 27),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port34, port_range, 28),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port35, port_range, 29),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port36, port_range, 30),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port37, port_range, 31),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port40, port_range, 32),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port41, port_range, 33),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port42, port_range, 34),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port43, port_range, 35),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port44, port_range, 36),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port45, port_range, 37),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port46, port_range, 38),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port47, port_range, 39),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port50, port_range, 40),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port51, port_range, 41),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port52, port_range, 42),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range, 43),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range, 44),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range, 45),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range, 46),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range, 47),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range, 48),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port61, port_range, 49),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port62, port_range, 50),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range, 51),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range, 52),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range, 53),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range, 54),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range, 55),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range, 56),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range, 57),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range, 58),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range, 59),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range, 60),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range, 61),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range, 62),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range, 63),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range, 64),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range, 65),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range, 66),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range, 67),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range, 68),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range, 69),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range, 70),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range, 71),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range, 72),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range, 73),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range, 74),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range, 75),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range, 76),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range, 77),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range, 78),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range, 79),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range, 80),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range, 81),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range, 82),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range, 83),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range, 84),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range, 85),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range, 86),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range, 87),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range, 96),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range, 97),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range, 98),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range, 99),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range, 100),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range, 101),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range, 102),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range, 103),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range, 104),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range, 105),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range, 106),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range, 107),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range, 108),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range, 109),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range, 110),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range, 111),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range, 112),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range, 113),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range, 114),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range, 115),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range, 116),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range, 117),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range, 118),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range, 119),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port180, port_range, 144),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port181, port_range, 145),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port182, port_range, 146),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port183, port_range, 147),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port184, port_range, 148),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port185, port_range, 149),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port186, port_range, 150),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port187, port_range, 151),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port200, port_range, 160),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port201, port_range, 161),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port202, port_range, 162),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port203, port_range, 163),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port204, port_range, 164),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port205, port_range, 165),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port206, port_range, 166),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port207, port_range, 167),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port210, port_range, 168),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port211, port_range, 169),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port212, port_range, 170),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port213, port_range, 171),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port214, port_range, 172),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port215, port_range, 173),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port216, port_range, 174),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port217, port_range, 175),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port220, port_range, 176),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port221, port_range, 177),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port222, port_range, 178),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port223, port_range, 179),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port224, port_range, 180),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port225, port_range, 181),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port226, port_range, 182),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port227, port_range, 183),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port230, port_range, 184),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port231, port_range, 185),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port232, port_range, 186),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port233, port_range, 187),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port234, port_range, 188),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port235, port_range, 189),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port236, port_range, 190),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port237, port_range, 191),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port240, port_range, 192),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port241, port_range, 193),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port242, port_range, 194),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port243, port_range, 195),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port244, port_range, 196),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port245, port_range, 197),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port246, port_range, 198),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port247, port_range, 199),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port250, port_range, 200),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port251, port_range, 201),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port252, port_range, 202),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port253, port_range, 203),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(port254, port_range, 204),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0, xirq, 0),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1, xirq, 1),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2, xirq, 2),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3, xirq, 3),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4, xirq, 4),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5, xirq, 5),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6, xirq, 6),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7, xirq, 7),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8, xirq, 8),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9, xirq, 9),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10, xirq, 10),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11, xirq, 11),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq12, xirq, 12),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq13, xirq, 13),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14, xirq, 14),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq15, xirq, 15),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq16, xirq, 16),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17, xirq, 17),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18, xirq, 18),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq19, xirq, 19),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq20, xirq, 20),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq21, xirq, 21),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq22, xirq, 22),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq23, xirq, 23),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0b, xirq_alternatives, 0),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1b, xirq_alternatives, 1),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2b, xirq_alternatives, 2),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3b, xirq_alternatives, 3),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4b, xirq_alternatives, 4),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5b, xirq_alternatives, 5),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6b, xirq_alternatives, 6),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7b, xirq_alternatives, 7),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8b, xirq_alternatives, 8),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9b, xirq_alternatives, 9),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10b, xirq_alternatives, 10),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11b, xirq_alternatives, 11),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq13b, xirq_alternatives, 12),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14b, xirq_alternatives, 13),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq16b, xirq_alternatives, 14),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17b, xirq_alternatives, 15),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18b, xirq_alternatives, 16),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq19b, xirq_alternatives, 17),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq20b, xirq_alternatives, 18),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq21b, xirq_alternatives, 19),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq22b, xirq_alternatives, 20),
+       UNIPHIER_PINCTRL_GROUP_SINGLE(xirq23b, xirq_alternatives, 21),
+};
+
+static const char * const emmc_groups[] = {"emmc", "emmc_dat8"};
+static const char * const ether_rgmii_groups[] = {"ether_rgmii"};
+static const char * const ether_rmii_groups[] = {"ether_rmii"};
+static const char * const i2c0_groups[] = {"i2c0"};
+static const char * const i2c1_groups[] = {"i2c1"};
+static const char * const i2c3_groups[] = {"i2c3"};
+static const char * const i2c4_groups[] = {"i2c4"};
+static const char * const nand_groups[] = {"nand"};
+static const char * const sd_groups[] = {"sd"};
+static const char * const system_bus_groups[] = {"system_bus",
+                                                "system_bus_cs1"};
+static const char * const uart0_groups[] = {"uart0"};
+static const char * const uart1_groups[] = {"uart1"};
+static const char * const uart2_groups[] = {"uart2"};
+static const char * const uart3_groups[] = {"uart3"};
+static const char * const usb0_groups[] = {"usb0"};
+static const char * const usb1_groups[] = {"usb1"};
+static const char * const usb2_groups[] = {"usb2"};
+static const char * const usb3_groups[] = {"usb3"};
+static const char * const port_groups[] = {
+       "port00", "port01", "port02", "port03",
+       "port04", "port05", "port06", "port07",
+       "port10", "port11", "port12", "port13",
+       "port14", "port15", "port16", "port17",
+       "port20", "port21", "port22", "port23",
+       "port24", "port25", "port26", "port27",
+       "port30", "port31", "port32", "port33",
+       "port34", "port35", "port36", "port37",
+       "port40", "port41", "port42", "port43",
+       "port44", "port45", "port46", "port47",
+       "port50", "port51", "port52", "port53",
+       "port54", "port55", "port56", "port57",
+       "port60", "port61", "port62", "port63",
+       "port64", "port65", "port66", "port67",
+       "port70", "port71", "port72", "port73",
+       "port74", "port75", "port76", "port77",
+       "port80", "port81", "port82", "port83",
+       "port84", "port85", "port86", "port87",
+       "port90", "port91", "port92", "port93",
+       "port94", "port95", "port96", "port97",
+       "port100", "port101", "port102", "port103",
+       "port104", "port105", "port106", "port107",
+       /* port110-117 missing */
+       "port120", "port121", "port122", "port123",
+       "port124", "port125", "port126", "port127",
+       "port130", "port131", "port132", "port133",
+       "port134", "port135", "port136", "port137",
+       "port140", "port141", "port142", "port143",
+       "port144", "port145", "port146", "port147",
+       /* port150-177 missing */
+       "port180", "port181", "port182", "port183",
+       "port184", "port185", "port186", "port187",
+       /* port190-197 missing */
+       "port200", "port201", "port202", "port203",
+       "port204", "port205", "port206", "port207",
+       "port210", "port211", "port212", "port213",
+       "port214", "port215", "port216", "port217",
+       "port220", "port221", "port222", "port223",
+       "port224", "port225", "port226", "port227",
+       "port230", "port231", "port232", "port233",
+       "port234", "port235", "port236", "port237",
+       "port240", "port241", "port242", "port243",
+       "port244", "port245", "port246", "port247",
+       "port250", "port251", "port252", "port253",
+       "port254",
+};
+static const char * const xirq_groups[] = {
+       "xirq0",  "xirq1",  "xirq2",  "xirq3",
+       "xirq4",  "xirq5",  "xirq6",  "xirq7",
+       "xirq8",  "xirq9",  "xirq10", "xirq11",
+       "xirq12", "xirq13", "xirq14", "xirq15",
+       "xirq16", "xirq17", "xirq18", "xirq19",
+       "xirq20", "xirq21", "xirq22", "xirq23",
+       "xirq0b",  "xirq1b",  "xirq2b",  "xirq3b",
+       "xirq4b",  "xirq5b",  "xirq6b",  "xirq7b",
+       "xirq8b",  "xirq9b",  "xirq10b", "xirq11b",
+       /* none */ "xirq13b", "xirq14b", /* none */
+       "xirq16b", "xirq17b", "xirq18b", "xirq19b",
+       "xirq20b", "xirq21b", "xirq22b", "xirq23b",
+};
+
+static const struct uniphier_pinmux_function uniphier_ld20_functions[] = {
+       UNIPHIER_PINMUX_FUNCTION(emmc),
+       UNIPHIER_PINMUX_FUNCTION(ether_rgmii),
+       UNIPHIER_PINMUX_FUNCTION(ether_rmii),
+       UNIPHIER_PINMUX_FUNCTION(i2c0),
+       UNIPHIER_PINMUX_FUNCTION(i2c1),
+       UNIPHIER_PINMUX_FUNCTION(i2c3),
+       UNIPHIER_PINMUX_FUNCTION(i2c4),
+       UNIPHIER_PINMUX_FUNCTION(nand),
+       UNIPHIER_PINMUX_FUNCTION(sd),
+       UNIPHIER_PINMUX_FUNCTION(system_bus),
+       UNIPHIER_PINMUX_FUNCTION(uart0),
+       UNIPHIER_PINMUX_FUNCTION(uart1),
+       UNIPHIER_PINMUX_FUNCTION(uart2),
+       UNIPHIER_PINMUX_FUNCTION(uart3),
+       UNIPHIER_PINMUX_FUNCTION(usb0),
+       UNIPHIER_PINMUX_FUNCTION(usb1),
+       UNIPHIER_PINMUX_FUNCTION(usb2),
+       UNIPHIER_PINMUX_FUNCTION(usb3),
+       UNIPHIER_PINMUX_FUNCTION(port),
+       UNIPHIER_PINMUX_FUNCTION(xirq),
+};
+
+static struct uniphier_pinctrl_socdata uniphier_ld20_pindata = {
+       .pins = uniphier_ld20_pins,
+       .npins = ARRAY_SIZE(uniphier_ld20_pins),
+       .groups = uniphier_ld20_groups,
+       .groups_count = ARRAY_SIZE(uniphier_ld20_groups),
+       .functions = uniphier_ld20_functions,
+       .functions_count = ARRAY_SIZE(uniphier_ld20_functions),
+       .caps = UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL,
+};
+
+static int uniphier_ld20_pinctrl_probe(struct platform_device *pdev)
+{
+       return uniphier_pinctrl_probe(pdev, &uniphier_ld20_pindata);
+}
+
+static const struct of_device_id uniphier_ld20_pinctrl_match[] = {
+       { .compatible = "socionext,uniphier-ld20-pinctrl" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_ld20_pinctrl_match);
+
+static struct platform_driver uniphier_ld20_pinctrl_driver = {
+       .probe = uniphier_ld20_pinctrl_probe,
+       .driver = {
+               .name = "uniphier-ld20-pinctrl",
+               .of_match_table = uniphier_ld20_pinctrl_match,
+       },
+};
+module_platform_driver(uniphier_ld20_pinctrl_driver);
+
+MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier PH1-LD20 pinctrl driver");
+MODULE_LICENSE("GPL");
index 4a0439c..3edfb6f 100644 (file)
 
 #include "pinctrl-uniphier.h"
 
-#define DRIVER_NAME "ph1-ld4-pinctrl"
-
-static const struct pinctrl_pin_desc ph1_ld4_pins[] = {
+static const struct pinctrl_pin_desc uniphier_ld4_pins[] = {
        UNIPHIER_PINCTRL_PIN(0, "EA1", UNIPHIER_PIN_IECTRL_NONE,
-                            8, UNIPHIER_PIN_DRV_4_8,
+                            8, UNIPHIER_PIN_DRV_1BIT,
                             8, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(1, "EA2", UNIPHIER_PIN_IECTRL_NONE,
-                            9, UNIPHIER_PIN_DRV_4_8,
+                            9, UNIPHIER_PIN_DRV_1BIT,
                             9, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(2, "EA3", UNIPHIER_PIN_IECTRL_NONE,
-                            10, UNIPHIER_PIN_DRV_4_8,
+                            10, UNIPHIER_PIN_DRV_1BIT,
                             10, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(3, "EA4", UNIPHIER_PIN_IECTRL_NONE,
-                            11, UNIPHIER_PIN_DRV_4_8,
+                            11, UNIPHIER_PIN_DRV_1BIT,
                             11, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(4, "EA5", UNIPHIER_PIN_IECTRL_NONE,
-                            12, UNIPHIER_PIN_DRV_4_8,
+                            12, UNIPHIER_PIN_DRV_1BIT,
                             12, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(5, "EA6", UNIPHIER_PIN_IECTRL_NONE,
-                            13, UNIPHIER_PIN_DRV_4_8,
+                            13, UNIPHIER_PIN_DRV_1BIT,
                             13, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(6, "EA7", UNIPHIER_PIN_IECTRL_NONE,
-                            14, UNIPHIER_PIN_DRV_4_8,
+                            14, UNIPHIER_PIN_DRV_1BIT,
                             14, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(7, "EA8", 0,
-                            15, UNIPHIER_PIN_DRV_4_8,
+                            15, UNIPHIER_PIN_DRV_1BIT,
                             15, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(8, "EA9", 0,
-                            16, UNIPHIER_PIN_DRV_4_8,
+                            16, UNIPHIER_PIN_DRV_1BIT,
                             16, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(9, "EA10", 0,
-                            17, UNIPHIER_PIN_DRV_4_8,
+                            17, UNIPHIER_PIN_DRV_1BIT,
                             17, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(10, "EA11", 0,
-                            18, UNIPHIER_PIN_DRV_4_8,
+                            18, UNIPHIER_PIN_DRV_1BIT,
                             18, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(11, "EA12", 0,
-                            19, UNIPHIER_PIN_DRV_4_8,
+                            19, UNIPHIER_PIN_DRV_1BIT,
                             19, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(12, "EA13", 0,
-                            20, UNIPHIER_PIN_DRV_4_8,
+                            20, UNIPHIER_PIN_DRV_1BIT,
                             20, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(13, "EA14", 0,
-                            21, UNIPHIER_PIN_DRV_4_8,
+                            21, UNIPHIER_PIN_DRV_1BIT,
                             21, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(14, "EA15", 0,
-                            22, UNIPHIER_PIN_DRV_4_8,
+                            22, UNIPHIER_PIN_DRV_1BIT,
                             22, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(15, "ECLK", UNIPHIER_PIN_IECTRL_NONE,
-                            23, UNIPHIER_PIN_DRV_4_8,
+                            23, UNIPHIER_PIN_DRV_1BIT,
                             23, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(16, "XERWE0", UNIPHIER_PIN_IECTRL_NONE,
-                            24, UNIPHIER_PIN_DRV_4_8,
+                            24, UNIPHIER_PIN_DRV_1BIT,
                             24, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(17, "XERWE1", UNIPHIER_PIN_IECTRL_NONE,
-                            25, UNIPHIER_PIN_DRV_4_8,
+                            25, UNIPHIER_PIN_DRV_1BIT,
                             25, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(18, "ES0", UNIPHIER_PIN_IECTRL_NONE,
-                            27, UNIPHIER_PIN_DRV_4_8,
+                            27, UNIPHIER_PIN_DRV_1BIT,
                             27, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(19, "ES1", UNIPHIER_PIN_IECTRL_NONE,
-                            28, UNIPHIER_PIN_DRV_4_8,
+                            28, UNIPHIER_PIN_DRV_1BIT,
                             28, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(20, "ES2", UNIPHIER_PIN_IECTRL_NONE,
-                            29, UNIPHIER_PIN_DRV_4_8,
+                            29, UNIPHIER_PIN_DRV_1BIT,
                             29, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(21, "XERST", UNIPHIER_PIN_IECTRL_NONE,
-                            38, UNIPHIER_PIN_DRV_4_8,
+                            38, UNIPHIER_PIN_DRV_1BIT,
                             38, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(22, "MMCCLK", UNIPHIER_PIN_IECTRL_NONE,
-                            0, UNIPHIER_PIN_DRV_8_12_16_20,
+                            0, UNIPHIER_PIN_DRV_2BIT,
                             146, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(23, "MMCCMD", UNIPHIER_PIN_IECTRL_NONE,
-                            4, UNIPHIER_PIN_DRV_8_12_16_20,
+                            1, UNIPHIER_PIN_DRV_2BIT,
                             147, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(24, "MMCDAT0", UNIPHIER_PIN_IECTRL_NONE,
-                            8, UNIPHIER_PIN_DRV_8_12_16_20,
+                            2, UNIPHIER_PIN_DRV_2BIT,
                             148, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(25, "MMCDAT1", UNIPHIER_PIN_IECTRL_NONE,
-                            12, UNIPHIER_PIN_DRV_8_12_16_20,
+                            3, UNIPHIER_PIN_DRV_2BIT,
                             149, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(26, "MMCDAT2", UNIPHIER_PIN_IECTRL_NONE,
-                            16, UNIPHIER_PIN_DRV_8_12_16_20,
+                            4, UNIPHIER_PIN_DRV_2BIT,
                             150, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(27, "MMCDAT3", UNIPHIER_PIN_IECTRL_NONE,
-                            20, UNIPHIER_PIN_DRV_8_12_16_20,
+                            5, UNIPHIER_PIN_DRV_2BIT,
                             151, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(28, "MMCDAT4", UNIPHIER_PIN_IECTRL_NONE,
-                            24, UNIPHIER_PIN_DRV_8_12_16_20,
+                            6, UNIPHIER_PIN_DRV_2BIT,
                             152, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(29, "MMCDAT5", UNIPHIER_PIN_IECTRL_NONE,
-                            28, UNIPHIER_PIN_DRV_8_12_16_20,
+                            7, UNIPHIER_PIN_DRV_2BIT,
                             153, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(30, "MMCDAT6", UNIPHIER_PIN_IECTRL_NONE,
-                            32, UNIPHIER_PIN_DRV_8_12_16_20,
+                            8, UNIPHIER_PIN_DRV_2BIT,
                             154, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(31, "MMCDAT7", UNIPHIER_PIN_IECTRL_NONE,
-                            36, UNIPHIER_PIN_DRV_8_12_16_20,
+                            9, UNIPHIER_PIN_DRV_2BIT,
                             155, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(32, "RMII_RXD0", 6,
-                            39, UNIPHIER_PIN_DRV_4_8,
+                            39, UNIPHIER_PIN_DRV_1BIT,
                             39, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(33, "RMII_RXD1", 6,
-                            40, UNIPHIER_PIN_DRV_4_8,
+                            40, UNIPHIER_PIN_DRV_1BIT,
                             40, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(34, "RMII_CRS_DV", 6,
-                            41, UNIPHIER_PIN_DRV_4_8,
+                            41, UNIPHIER_PIN_DRV_1BIT,
                             41, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(35, "RMII_RXER", 6,
-                            42, UNIPHIER_PIN_DRV_4_8,
+                            42, UNIPHIER_PIN_DRV_1BIT,
                             42, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(36, "RMII_REFCLK", 6,
-                            43, UNIPHIER_PIN_DRV_4_8,
+                            43, UNIPHIER_PIN_DRV_1BIT,
                             43, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(37, "RMII_TXD0", 6,
-                            44, UNIPHIER_PIN_DRV_4_8,
+                            44, UNIPHIER_PIN_DRV_1BIT,
                             44, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(38, "RMII_TXD1", 6,
-                            45, UNIPHIER_PIN_DRV_4_8,
+                            45, UNIPHIER_PIN_DRV_1BIT,
                             45, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(39, "RMII_TXEN", 6,
-                            46, UNIPHIER_PIN_DRV_4_8,
+                            46, UNIPHIER_PIN_DRV_1BIT,
                             46, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(40, "MDC", 6,
-                            47, UNIPHIER_PIN_DRV_4_8,
+                            47, UNIPHIER_PIN_DRV_1BIT,
                             47, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(41, "MDIO", 6,
-                            48, UNIPHIER_PIN_DRV_4_8,
+                            48, UNIPHIER_PIN_DRV_1BIT,
                             48, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(42, "MDIO_INTL", 6,
-                            49, UNIPHIER_PIN_DRV_4_8,
+                            49, UNIPHIER_PIN_DRV_1BIT,
                             49, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(43, "PHYRSTL", 6,
-                            50, UNIPHIER_PIN_DRV_4_8,
+                            50, UNIPHIER_PIN_DRV_1BIT,
                             50, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(44, "SDCLK", UNIPHIER_PIN_IECTRL_NONE,
-                            40, UNIPHIER_PIN_DRV_8_12_16_20,
+                            10, UNIPHIER_PIN_DRV_2BIT,
                             156, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(45, "SDCMD", UNIPHIER_PIN_IECTRL_NONE,
-                            44, UNIPHIER_PIN_DRV_8_12_16_20,
+                            11, UNIPHIER_PIN_DRV_2BIT,
                             157, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(46, "SDDAT0", UNIPHIER_PIN_IECTRL_NONE,
-                            48, UNIPHIER_PIN_DRV_8_12_16_20,
+                            12, UNIPHIER_PIN_DRV_2BIT,
                             158, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(47, "SDDAT1", UNIPHIER_PIN_IECTRL_NONE,
-                            52, UNIPHIER_PIN_DRV_8_12_16_20,
+                            13, UNIPHIER_PIN_DRV_2BIT,
                             159, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(48, "SDDAT2", UNIPHIER_PIN_IECTRL_NONE,
-                            56, UNIPHIER_PIN_DRV_8_12_16_20,
+                            14, UNIPHIER_PIN_DRV_2BIT,
                             160, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(49, "SDDAT3", UNIPHIER_PIN_IECTRL_NONE,
-                            60, UNIPHIER_PIN_DRV_8_12_16_20,
+                            15, UNIPHIER_PIN_DRV_2BIT,
                             161, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(50, "SDCD", UNIPHIER_PIN_IECTRL_NONE,
-                            51, UNIPHIER_PIN_DRV_4_8,
+                            51, UNIPHIER_PIN_DRV_1BIT,
                             51, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(51, "SDWP", UNIPHIER_PIN_IECTRL_NONE,
-                            52, UNIPHIER_PIN_DRV_4_8,
+                            52, UNIPHIER_PIN_DRV_1BIT,
                             52, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(52, "SDVOLC", UNIPHIER_PIN_IECTRL_NONE,
-                            53, UNIPHIER_PIN_DRV_4_8,
+                            53, UNIPHIER_PIN_DRV_1BIT,
                             53, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(53, "USB0VBUS", 0,
-                            54, UNIPHIER_PIN_DRV_4_8,
+                            54, UNIPHIER_PIN_DRV_1BIT,
                             54, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(54, "USB0OD", 0,
-                            55, UNIPHIER_PIN_DRV_4_8,
+                            55, UNIPHIER_PIN_DRV_1BIT,
                             55, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(55, "USB1VBUS", 0,
-                            56, UNIPHIER_PIN_DRV_4_8,
+                            56, UNIPHIER_PIN_DRV_1BIT,
                             56, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(56, "USB1OD", 0,
-                            57, UNIPHIER_PIN_DRV_4_8,
+                            57, UNIPHIER_PIN_DRV_1BIT,
                             57, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(57, "PCRESET", 0,
-                            58, UNIPHIER_PIN_DRV_4_8,
+                            58, UNIPHIER_PIN_DRV_1BIT,
                             58, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(58, "PCREG", 0,
-                            59, UNIPHIER_PIN_DRV_4_8,
+                            59, UNIPHIER_PIN_DRV_1BIT,
                             59, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(59, "PCCE2", 0,
-                            60, UNIPHIER_PIN_DRV_4_8,
+                            60, UNIPHIER_PIN_DRV_1BIT,
                             60, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(60, "PCVS1", 0,
-                            61, UNIPHIER_PIN_DRV_4_8,
+                            61, UNIPHIER_PIN_DRV_1BIT,
                             61, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(61, "PCCD2", 0,
-                            62, UNIPHIER_PIN_DRV_4_8,
+                            62, UNIPHIER_PIN_DRV_1BIT,
                             62, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(62, "PCCD1", 0,
-                            63, UNIPHIER_PIN_DRV_4_8,
+                            63, UNIPHIER_PIN_DRV_1BIT,
                             63, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(63, "PCREADY", 0,
-                            64, UNIPHIER_PIN_DRV_4_8,
+                            64, UNIPHIER_PIN_DRV_1BIT,
                             64, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(64, "PCDOE", 0,
-                            65, UNIPHIER_PIN_DRV_4_8,
+                            65, UNIPHIER_PIN_DRV_1BIT,
                             65, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(65, "PCCE1", 0,
-                            66, UNIPHIER_PIN_DRV_4_8,
+                            66, UNIPHIER_PIN_DRV_1BIT,
                             66, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(66, "PCWE", 0,
-                            67, UNIPHIER_PIN_DRV_4_8,
+                            67, UNIPHIER_PIN_DRV_1BIT,
                             67, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(67, "PCOE", 0,
-                            68, UNIPHIER_PIN_DRV_4_8,
+                            68, UNIPHIER_PIN_DRV_1BIT,
                             68, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(68, "PCWAIT", 0,
-                            69, UNIPHIER_PIN_DRV_4_8,
+                            69, UNIPHIER_PIN_DRV_1BIT,
                             69, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(69, "PCIOWR", 0,
-                            70, UNIPHIER_PIN_DRV_4_8,
+                            70, UNIPHIER_PIN_DRV_1BIT,
                             70, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(70, "PCIORD", 0,
-                            71, UNIPHIER_PIN_DRV_4_8,
+                            71, UNIPHIER_PIN_DRV_1BIT,
                             71, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(71, "HS0DIN0", 0,
-                            72, UNIPHIER_PIN_DRV_4_8,
+                            72, UNIPHIER_PIN_DRV_1BIT,
                             72, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(72, "HS0DIN1", 0,
-                            73, UNIPHIER_PIN_DRV_4_8,
+                            73, UNIPHIER_PIN_DRV_1BIT,
                             73, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(73, "HS0DIN2", 0,
-                            74, UNIPHIER_PIN_DRV_4_8,
+                            74, UNIPHIER_PIN_DRV_1BIT,
                             74, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(74, "HS0DIN3", 0,
-                            75, UNIPHIER_PIN_DRV_4_8,
+                            75, UNIPHIER_PIN_DRV_1BIT,
                             75, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(75, "HS0DIN4", 0,
-                            76, UNIPHIER_PIN_DRV_4_8,
+                            76, UNIPHIER_PIN_DRV_1BIT,
                             76, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(76, "HS0DIN5", 0,
-                            77, UNIPHIER_PIN_DRV_4_8,
+                            77, UNIPHIER_PIN_DRV_1BIT,
                             77, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(77, "HS0DIN6", 0,
-                            78, UNIPHIER_PIN_DRV_4_8,
+                            78, UNIPHIER_PIN_DRV_1BIT,
                             78, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(78, "HS0DIN7", 0,
-                            79, UNIPHIER_PIN_DRV_4_8,
+                            79, UNIPHIER_PIN_DRV_1BIT,
                             79, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(79, "HS0BCLKIN", 0,
-                            80, UNIPHIER_PIN_DRV_4_8,
+                            80, UNIPHIER_PIN_DRV_1BIT,
                             80, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(80, "HS0VALIN", 0,
-                            81, UNIPHIER_PIN_DRV_4_8,
+                            81, UNIPHIER_PIN_DRV_1BIT,
                             81, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(81, "HS0SYNCIN", 0,
-                            82, UNIPHIER_PIN_DRV_4_8,
+                            82, UNIPHIER_PIN_DRV_1BIT,
                             82, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(82, "HSDOUT0", 0,
-                            83, UNIPHIER_PIN_DRV_4_8,
+                            83, UNIPHIER_PIN_DRV_1BIT,
                             83, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(83, "HSDOUT1", 0,
-                            84, UNIPHIER_PIN_DRV_4_8,
+                            84, UNIPHIER_PIN_DRV_1BIT,
                             84, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(84, "HSDOUT2", 0,
-                            85, UNIPHIER_PIN_DRV_4_8,
+                            85, UNIPHIER_PIN_DRV_1BIT,
                             85, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(85, "HSDOUT3", 0,
-                            86, UNIPHIER_PIN_DRV_4_8,
+                            86, UNIPHIER_PIN_DRV_1BIT,
                             86, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(86, "HSDOUT4", 0,
-                            87, UNIPHIER_PIN_DRV_4_8,
+                            87, UNIPHIER_PIN_DRV_1BIT,
                             87, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(87, "HSDOUT5", 0,
-                            88, UNIPHIER_PIN_DRV_4_8,
+                            88, UNIPHIER_PIN_DRV_1BIT,
                             88, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(88, "HSDOUT6", 0,
-                            89, UNIPHIER_PIN_DRV_4_8,
+                            89, UNIPHIER_PIN_DRV_1BIT,
                             89, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(89, "HSDOUT7", 0,
-                            90, UNIPHIER_PIN_DRV_4_8,
+                            90, UNIPHIER_PIN_DRV_1BIT,
                             90, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(90, "HSBCLKOUT", 0,
-                            91, UNIPHIER_PIN_DRV_4_8,
+                            91, UNIPHIER_PIN_DRV_1BIT,
                             91, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(91, "HSVALOUT", 0,
-                            92, UNIPHIER_PIN_DRV_4_8,
+                            92, UNIPHIER_PIN_DRV_1BIT,
                             92, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(92, "HSSYNCOUT", 0,
-                            93, UNIPHIER_PIN_DRV_4_8,
+                            93, UNIPHIER_PIN_DRV_1BIT,
                             93, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(93, "AGCI", 3,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             162, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(94, "AGCR", 4,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             163, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(95, "AGCBS", 5,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             164, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(96, "IECOUT", 0,
-                            94, UNIPHIER_PIN_DRV_4_8,
+                            94, UNIPHIER_PIN_DRV_1BIT,
                             94, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(97, "ASMCK", 0,
-                            95, UNIPHIER_PIN_DRV_4_8,
+                            95, UNIPHIER_PIN_DRV_1BIT,
                             95, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(98, "ABCKO", UNIPHIER_PIN_IECTRL_NONE,
-                            96, UNIPHIER_PIN_DRV_4_8,
+                            96, UNIPHIER_PIN_DRV_1BIT,
                             96, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(99, "ALRCKO", UNIPHIER_PIN_IECTRL_NONE,
-                            97, UNIPHIER_PIN_DRV_4_8,
+                            97, UNIPHIER_PIN_DRV_1BIT,
                             97, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(100, "ASDOUT0", UNIPHIER_PIN_IECTRL_NONE,
-                            98, UNIPHIER_PIN_DRV_4_8,
+                            98, UNIPHIER_PIN_DRV_1BIT,
                             98, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(101, "ARCOUT", 0,
-                            99, UNIPHIER_PIN_DRV_4_8,
+                            99, UNIPHIER_PIN_DRV_1BIT,
                             99, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(102, "SDA0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(103, "SCL0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(104, "SDA1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(105, "SCL1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(106, "DMDSDA0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(107, "DMDSCL0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(108, "DMDSDA1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(109, "DMDSCL1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(110, "SBO0", UNIPHIER_PIN_IECTRL_NONE,
-                            100, UNIPHIER_PIN_DRV_4_8,
+                            100, UNIPHIER_PIN_DRV_1BIT,
                             100, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(111, "SBI0", UNIPHIER_PIN_IECTRL_NONE,
-                            101, UNIPHIER_PIN_DRV_4_8,
+                            101, UNIPHIER_PIN_DRV_1BIT,
                             101, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(112, "HIN", 1,
-                            -1, UNIPHIER_PIN_DRV_FIXED_5,
+                            -1, UNIPHIER_PIN_DRV_FIXED5,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(113, "VIN", 2,
-                            -1, UNIPHIER_PIN_DRV_FIXED_5,
+                            -1, UNIPHIER_PIN_DRV_FIXED5,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(114, "TCON0", UNIPHIER_PIN_IECTRL_NONE,
-                            102, UNIPHIER_PIN_DRV_4_8,
+                            102, UNIPHIER_PIN_DRV_1BIT,
                             102, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(115, "TCON1", UNIPHIER_PIN_IECTRL_NONE,
-                            103, UNIPHIER_PIN_DRV_4_8,
+                            103, UNIPHIER_PIN_DRV_1BIT,
                             103, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(116, "TCON2", UNIPHIER_PIN_IECTRL_NONE,
-                            104, UNIPHIER_PIN_DRV_4_8,
+                            104, UNIPHIER_PIN_DRV_1BIT,
                             104, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(117, "TCON3", UNIPHIER_PIN_IECTRL_NONE,
-                            105, UNIPHIER_PIN_DRV_4_8,
+                            105, UNIPHIER_PIN_DRV_1BIT,
                             105, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(118, "TCON4", UNIPHIER_PIN_IECTRL_NONE,
-                            106, UNIPHIER_PIN_DRV_4_8,
+                            106, UNIPHIER_PIN_DRV_1BIT,
                             106, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(119, "TCON5", UNIPHIER_PIN_IECTRL_NONE,
-                            107, UNIPHIER_PIN_DRV_4_8,
+                            107, UNIPHIER_PIN_DRV_1BIT,
                             107, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(120, "TCON6", 0,
-                            108, UNIPHIER_PIN_DRV_4_8,
+                            108, UNIPHIER_PIN_DRV_1BIT,
                             108, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(121, "TCON7", 0,
-                            109, UNIPHIER_PIN_DRV_4_8,
+                            109, UNIPHIER_PIN_DRV_1BIT,
                             109, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(122, "PWMA", 0,
-                            110, UNIPHIER_PIN_DRV_4_8,
+                            110, UNIPHIER_PIN_DRV_1BIT,
                             110, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(123, "XIRQ1", 0,
-                            111, UNIPHIER_PIN_DRV_4_8,
+                            111, UNIPHIER_PIN_DRV_1BIT,
                             111, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(124, "XIRQ2", 0,
-                            112, UNIPHIER_PIN_DRV_4_8,
+                            112, UNIPHIER_PIN_DRV_1BIT,
                             112, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(125, "XIRQ3", 0,
-                            113, UNIPHIER_PIN_DRV_4_8,
+                            113, UNIPHIER_PIN_DRV_1BIT,
                             113, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(126, "XIRQ4", 0,
-                            114, UNIPHIER_PIN_DRV_4_8,
+                            114, UNIPHIER_PIN_DRV_1BIT,
                             114, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(127, "XIRQ5", 0,
-                            115, UNIPHIER_PIN_DRV_4_8,
+                            115, UNIPHIER_PIN_DRV_1BIT,
                             115, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(128, "XIRQ6", 0,
-                            116, UNIPHIER_PIN_DRV_4_8,
+                            116, UNIPHIER_PIN_DRV_1BIT,
                             116, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(129, "XIRQ7", 0,
-                            117, UNIPHIER_PIN_DRV_4_8,
+                            117, UNIPHIER_PIN_DRV_1BIT,
                             117, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(130, "XIRQ8", 0,
-                            118, UNIPHIER_PIN_DRV_4_8,
+                            118, UNIPHIER_PIN_DRV_1BIT,
                             118, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(131, "XIRQ9", 0,
-                            119, UNIPHIER_PIN_DRV_4_8,
+                            119, UNIPHIER_PIN_DRV_1BIT,
                             119, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(132, "XIRQ10", 0,
-                            120, UNIPHIER_PIN_DRV_4_8,
+                            120, UNIPHIER_PIN_DRV_1BIT,
                             120, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(133, "XIRQ11", 0,
-                            121, UNIPHIER_PIN_DRV_4_8,
+                            121, UNIPHIER_PIN_DRV_1BIT,
                             121, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(134, "XIRQ14", 0,
-                            122, UNIPHIER_PIN_DRV_4_8,
+                            122, UNIPHIER_PIN_DRV_1BIT,
                             122, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(135, "PORT00", 0,
-                            123, UNIPHIER_PIN_DRV_4_8,
+                            123, UNIPHIER_PIN_DRV_1BIT,
                             123, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(136, "PORT01", 0,
-                            124, UNIPHIER_PIN_DRV_4_8,
+                            124, UNIPHIER_PIN_DRV_1BIT,
                             124, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(137, "PORT02", 0,
-                            125, UNIPHIER_PIN_DRV_4_8,
+                            125, UNIPHIER_PIN_DRV_1BIT,
                             125, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(138, "PORT03", 0,
-                            126, UNIPHIER_PIN_DRV_4_8,
+                            126, UNIPHIER_PIN_DRV_1BIT,
                             126, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(139, "PORT04", 0,
-                            127, UNIPHIER_PIN_DRV_4_8,
+                            127, UNIPHIER_PIN_DRV_1BIT,
                             127, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(140, "PORT05", 0,
-                            128, UNIPHIER_PIN_DRV_4_8,
+                            128, UNIPHIER_PIN_DRV_1BIT,
                             128, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(141, "PORT06", 0,
-                            129, UNIPHIER_PIN_DRV_4_8,
+                            129, UNIPHIER_PIN_DRV_1BIT,
                             129, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(142, "PORT07", 0,
-                            130, UNIPHIER_PIN_DRV_4_8,
+                            130, UNIPHIER_PIN_DRV_1BIT,
                             130, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(143, "PORT10", 0,
-                            131, UNIPHIER_PIN_DRV_4_8,
+                            131, UNIPHIER_PIN_DRV_1BIT,
                             131, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(144, "PORT11", 0,
-                            132, UNIPHIER_PIN_DRV_4_8,
+                            132, UNIPHIER_PIN_DRV_1BIT,
                             132, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(145, "PORT12", 0,
-                            133, UNIPHIER_PIN_DRV_4_8,
+                            133, UNIPHIER_PIN_DRV_1BIT,
                             133, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(146, "PORT13", 0,
-                            134, UNIPHIER_PIN_DRV_4_8,
+                            134, UNIPHIER_PIN_DRV_1BIT,
                             134, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(147, "PORT14", 0,
-                            135, UNIPHIER_PIN_DRV_4_8,
+                            135, UNIPHIER_PIN_DRV_1BIT,
                             135, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(148, "PORT15", 0,
-                            136, UNIPHIER_PIN_DRV_4_8,
+                            136, UNIPHIER_PIN_DRV_1BIT,
                             136, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(149, "PORT16", 0,
-                            137, UNIPHIER_PIN_DRV_4_8,
+                            137, UNIPHIER_PIN_DRV_1BIT,
                             137, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(150, "PORT17", UNIPHIER_PIN_IECTRL_NONE,
-                            138, UNIPHIER_PIN_DRV_4_8,
+                            138, UNIPHIER_PIN_DRV_1BIT,
                             138, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(151, "PORT20", 0,
-                            139, UNIPHIER_PIN_DRV_4_8,
+                            139, UNIPHIER_PIN_DRV_1BIT,
                             139, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(152, "PORT21", 0,
-                            140, UNIPHIER_PIN_DRV_4_8,
+                            140, UNIPHIER_PIN_DRV_1BIT,
                             140, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(153, "PORT22", 0,
-                            141, UNIPHIER_PIN_DRV_4_8,
+                            141, UNIPHIER_PIN_DRV_1BIT,
                             141, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(154, "PORT23", 0,
-                            142, UNIPHIER_PIN_DRV_4_8,
+                            142, UNIPHIER_PIN_DRV_1BIT,
                             142, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(155, "PORT24", UNIPHIER_PIN_IECTRL_NONE,
-                            143, UNIPHIER_PIN_DRV_4_8,
+                            143, UNIPHIER_PIN_DRV_1BIT,
                             143, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(156, "PORT25", 0,
-                            144, UNIPHIER_PIN_DRV_4_8,
+                            144, UNIPHIER_PIN_DRV_1BIT,
                             144, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(157, "PORT26", 0,
-                            145, UNIPHIER_PIN_DRV_4_8,
+                            145, UNIPHIER_PIN_DRV_1BIT,
                             145, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(158, "XNFRE", UNIPHIER_PIN_IECTRL_NONE,
-                            31, UNIPHIER_PIN_DRV_4_8,
+                            31, UNIPHIER_PIN_DRV_1BIT,
                             31, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(159, "XNFWE", UNIPHIER_PIN_IECTRL_NONE,
-                            32, UNIPHIER_PIN_DRV_4_8,
+                            32, UNIPHIER_PIN_DRV_1BIT,
                             32, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(160, "NFALE", UNIPHIER_PIN_IECTRL_NONE,
-                            33, UNIPHIER_PIN_DRV_4_8,
+                            33, UNIPHIER_PIN_DRV_1BIT,
                             33, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(161, "NFCLE", UNIPHIER_PIN_IECTRL_NONE,
-                            34, UNIPHIER_PIN_DRV_4_8,
+                            34, UNIPHIER_PIN_DRV_1BIT,
                             34, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(162, "XNFWP", UNIPHIER_PIN_IECTRL_NONE,
-                            35, UNIPHIER_PIN_DRV_4_8,
+                            35, UNIPHIER_PIN_DRV_1BIT,
                             35, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(163, "XNFCE0", UNIPHIER_PIN_IECTRL_NONE,
-                            36, UNIPHIER_PIN_DRV_4_8,
+                            36, UNIPHIER_PIN_DRV_1BIT,
                             36, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(164, "NANDRYBY0", UNIPHIER_PIN_IECTRL_NONE,
-                            37, UNIPHIER_PIN_DRV_4_8,
+                            37, UNIPHIER_PIN_DRV_1BIT,
                             37, UNIPHIER_PIN_PULL_UP),
+       /* dedicated pins */
+       UNIPHIER_PINCTRL_PIN(165, "ED0", -1,
+                            0, UNIPHIER_PIN_DRV_1BIT,
+                            0, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(166, "ED1", -1,
+                            1, UNIPHIER_PIN_DRV_1BIT,
+                            1, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(167, "ED2", -1,
+                            2, UNIPHIER_PIN_DRV_1BIT,
+                            2, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(168, "ED3", -1,
+                            3, UNIPHIER_PIN_DRV_1BIT,
+                            3, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(169, "ED4", -1,
+                            4, UNIPHIER_PIN_DRV_1BIT,
+                            4, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(170, "ED5", -1,
+                            5, UNIPHIER_PIN_DRV_1BIT,
+                            5, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(171, "ED6", -1,
+                            6, UNIPHIER_PIN_DRV_1BIT,
+                            6, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(172, "ED7", -1,
+                            7, UNIPHIER_PIN_DRV_1BIT,
+                            7, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(173, "ERXW", -1,
+                            26, UNIPHIER_PIN_DRV_1BIT,
+                            26, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(174, "XECS1", -1,
+                            30, UNIPHIER_PIN_DRV_1BIT,
+                            30, UNIPHIER_PIN_PULL_UP),
 };
 
 static const unsigned emmc_pins[] = {21, 22, 23, 24, 25, 26, 27};
-static const unsigned emmc_muxvals[] = {0, 1, 1, 1, 1, 1, 1};
+static const int emmc_muxvals[] = {0, 1, 1, 1, 1, 1, 1};
 static const unsigned emmc_dat8_pins[] = {28, 29, 30, 31};
-static const unsigned emmc_dat8_muxvals[] = {1, 1, 1, 1};
+static const int emmc_dat8_muxvals[] = {1, 1, 1, 1};
+static const unsigned ether_mii_pins[] = {32, 33, 34, 35, 36, 37, 38, 39, 40,
+                                         41, 42, 43, 136, 137, 138, 139, 140,
+                                         141, 142};
+static const int ether_mii_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                       4, 4, 4, 4, 4, 4, 4};
+static const unsigned ether_rmii_pins[] = {32, 33, 34, 35, 36, 37, 38, 39, 40,
+                                          41, 42, 43};
+static const int ether_rmii_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 static const unsigned i2c0_pins[] = {102, 103};
-static const unsigned i2c0_muxvals[] = {0, 0};
+static const int i2c0_muxvals[] = {0, 0};
 static const unsigned i2c1_pins[] = {104, 105};
-static const unsigned i2c1_muxvals[] = {0, 0};
+static const int i2c1_muxvals[] = {0, 0};
 static const unsigned i2c2_pins[] = {108, 109};
-static const unsigned i2c2_muxvals[] = {2, 2};
+static const int i2c2_muxvals[] = {2, 2};
 static const unsigned i2c3_pins[] = {108, 109};
-static const unsigned i2c3_muxvals[] = {3, 3};
+static const int i2c3_muxvals[] = {3, 3};
 static const unsigned nand_pins[] = {24, 25, 26, 27, 28, 29, 30, 31, 158, 159,
                                     160, 161, 162, 163, 164};
-static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                                       0, 0};
+static const int nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 static const unsigned nand_cs1_pins[] = {22, 23};
-static const unsigned nand_cs1_muxvals[] = {0, 0};
+static const int nand_cs1_muxvals[] = {0, 0};
 static const unsigned sd_pins[] = {44, 45, 46, 47, 48, 49, 50, 51, 52};
-static const unsigned sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const int sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned system_bus_pins[] = {16, 17, 18, 19, 20, 165, 166, 167,
+                                          168, 169, 170, 171, 172, 173};
+static const int system_bus_muxvals[] = {0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1,
+                                        -1, -1, -1};
+static const unsigned system_bus_cs0_pins[] = {155};
+static const int system_bus_cs0_muxvals[] = {1};
+static const unsigned system_bus_cs1_pins[] = {174};
+static const int system_bus_cs1_muxvals[] = {-1};
+static const unsigned system_bus_cs2_pins[] = {64};
+static const int system_bus_cs2_muxvals[] = {1};
+static const unsigned system_bus_cs3_pins[] = {156};
+static const int system_bus_cs3_muxvals[] = {1};
 static const unsigned uart0_pins[] = {85, 88};
-static const unsigned uart0_muxvals[] = {1, 1};
+static const int uart0_muxvals[] = {1, 1};
 static const unsigned uart1_pins[] = {155, 156};
-static const unsigned uart1_muxvals[] = {13, 13};
+static const int uart1_muxvals[] = {13, 13};
 static const unsigned uart1b_pins[] = {69, 70};
-static const unsigned uart1b_muxvals[] = {23, 23};
+static const int uart1b_muxvals[] = {23, 23};
 static const unsigned uart2_pins[] = {128, 129};
-static const unsigned uart2_muxvals[] = {13, 13};
+static const int uart2_muxvals[] = {13, 13};
 static const unsigned uart3_pins[] = {110, 111};
-static const unsigned uart3_muxvals[] = {1, 1};
+static const int uart3_muxvals[] = {1, 1};
 static const unsigned usb0_pins[] = {53, 54};
-static const unsigned usb0_muxvals[] = {0, 0};
+static const int usb0_muxvals[] = {0, 0};
 static const unsigned usb1_pins[] = {55, 56};
-static const unsigned usb1_muxvals[] = {0, 0};
+static const int usb1_muxvals[] = {0, 0};
 static const unsigned usb2_pins[] = {155, 156};
-static const unsigned usb2_muxvals[] = {4, 4};
+static const int usb2_muxvals[] = {4, 4};
 static const unsigned usb2b_pins[] = {67, 68};
-static const unsigned usb2b_muxvals[] = {23, 23};
+static const int usb2b_muxvals[] = {23, 23};
 static const unsigned port_range0_pins[] = {
        135, 136, 137, 138, 139, 140, 141, 142,         /* PORT0x */
        143, 144, 145, 146, 147, 148, 149, 150,         /* PORT1x */
@@ -574,7 +622,7 @@ static const unsigned port_range0_pins[] = {
        98, 99, 100, 6, 101, 114, 115, 116,             /* PORT13x */
        103, 108, 21, 22, 23, 117, 118, 119,            /* PORT14x */
 };
-static const unsigned port_range0_muxvals[] = {
+static const int port_range0_muxvals[] = {
        0, 0, 0, 0, 0, 0, 0, 0,                         /* PORT0x */
        0, 0, 0, 0, 0, 0, 0, 0,                         /* PORT1x */
        0, 0, 0, 0, 0, 0, 0, 15,                        /* PORT2x */
@@ -594,27 +642,29 @@ static const unsigned port_range0_muxvals[] = {
 static const unsigned port_range1_pins[] = {
        7,                                              /* PORT166 */
 };
-static const unsigned port_range1_muxvals[] = {
+static const int port_range1_muxvals[] = {
        15,                                             /* PORT166 */
 };
 static const unsigned xirq_range0_pins[] = {
        151, 123, 124, 125, 126, 127, 128, 129,         /* XIRQ0-7 */
        130, 131, 132, 133, 62,                         /* XIRQ8-12 */
 };
-static const unsigned xirq_range0_muxvals[] = {
+static const int xirq_range0_muxvals[] = {
        14, 0, 0, 0, 0, 0, 0, 0,                        /* XIRQ0-7 */
        0, 0, 0, 0, 14,                                 /* XIRQ8-12 */
 };
 static const unsigned xirq_range1_pins[] = {
        134, 63,                                        /* XIRQ14-15 */
 };
-static const unsigned xirq_range1_muxvals[] = {
+static const int xirq_range1_muxvals[] = {
        0, 14,                                          /* XIRQ14-15 */
 };
 
-static const struct uniphier_pinctrl_group ph1_ld4_groups[] = {
+static const struct uniphier_pinctrl_group uniphier_ld4_groups[] = {
        UNIPHIER_PINCTRL_GROUP(emmc),
        UNIPHIER_PINCTRL_GROUP(emmc_dat8),
+       UNIPHIER_PINCTRL_GROUP(ether_mii),
+       UNIPHIER_PINCTRL_GROUP(ether_rmii),
        UNIPHIER_PINCTRL_GROUP(i2c0),
        UNIPHIER_PINCTRL_GROUP(i2c1),
        UNIPHIER_PINCTRL_GROUP(i2c2),
@@ -622,6 +672,11 @@ static const struct uniphier_pinctrl_group ph1_ld4_groups[] = {
        UNIPHIER_PINCTRL_GROUP(nand),
        UNIPHIER_PINCTRL_GROUP(nand_cs1),
        UNIPHIER_PINCTRL_GROUP(sd),
+       UNIPHIER_PINCTRL_GROUP(system_bus),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs0),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs1),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs2),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs3),
        UNIPHIER_PINCTRL_GROUP(uart0),
        UNIPHIER_PINCTRL_GROUP(uart1),
        UNIPHIER_PINCTRL_GROUP(uart1b),
@@ -774,12 +829,19 @@ static const struct uniphier_pinctrl_group ph1_ld4_groups[] = {
 };
 
 static const char * const emmc_groups[] = {"emmc", "emmc_dat8"};
+static const char * const ether_mii_groups[] = {"ether_mii"};
+static const char * const ether_rmii_groups[] = {"ether_rmii"};
 static const char * const i2c0_groups[] = {"i2c0"};
 static const char * const i2c1_groups[] = {"i2c1"};
 static const char * const i2c2_groups[] = {"i2c2"};
 static const char * const i2c3_groups[] = {"i2c3"};
 static const char * const nand_groups[] = {"nand", "nand_cs1"};
 static const char * const sd_groups[] = {"sd"};
+static const char * const system_bus_groups[] = {"system_bus",
+                                                "system_bus_cs0",
+                                                "system_bus_cs1",
+                                                "system_bus_cs2",
+                                                "system_bus_cs3"};
 static const char * const uart0_groups[] = {"uart0"};
 static const char * const uart1_groups[] = {"uart1", "uart1b"};
 static const char * const uart2_groups[] = {"uart2"};
@@ -828,14 +890,17 @@ static const char * const xirq_groups[] = {
        "xirq12", /* none*/ "xirq14", "xirq15",
 };
 
-static const struct uniphier_pinmux_function ph1_ld4_functions[] = {
+static const struct uniphier_pinmux_function uniphier_ld4_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(emmc),
+       UNIPHIER_PINMUX_FUNCTION(ether_mii),
+       UNIPHIER_PINMUX_FUNCTION(ether_rmii),
        UNIPHIER_PINMUX_FUNCTION(i2c0),
        UNIPHIER_PINMUX_FUNCTION(i2c1),
        UNIPHIER_PINMUX_FUNCTION(i2c2),
        UNIPHIER_PINMUX_FUNCTION(i2c3),
        UNIPHIER_PINMUX_FUNCTION(nand),
        UNIPHIER_PINMUX_FUNCTION(sd),
+       UNIPHIER_PINMUX_FUNCTION(system_bus),
        UNIPHIER_PINMUX_FUNCTION(uart0),
        UNIPHIER_PINMUX_FUNCTION(uart1),
        UNIPHIER_PINMUX_FUNCTION(uart2),
@@ -847,43 +912,36 @@ static const struct uniphier_pinmux_function ph1_ld4_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(xirq),
 };
 
-static struct uniphier_pinctrl_socdata ph1_ld4_pindata = {
-       .groups = ph1_ld4_groups,
-       .groups_count = ARRAY_SIZE(ph1_ld4_groups),
-       .functions = ph1_ld4_functions,
-       .functions_count = ARRAY_SIZE(ph1_ld4_functions),
-       .mux_bits = 8,
-       .reg_stride = 4,
-       .load_pinctrl = false,
-};
-
-static struct pinctrl_desc ph1_ld4_pinctrl_desc = {
-       .name = DRIVER_NAME,
-       .pins = ph1_ld4_pins,
-       .npins = ARRAY_SIZE(ph1_ld4_pins),
-       .owner = THIS_MODULE,
+static struct uniphier_pinctrl_socdata uniphier_ld4_pindata = {
+       .pins = uniphier_ld4_pins,
+       .npins = ARRAY_SIZE(uniphier_ld4_pins),
+       .groups = uniphier_ld4_groups,
+       .groups_count = ARRAY_SIZE(uniphier_ld4_groups),
+       .functions = uniphier_ld4_functions,
+       .functions_count = ARRAY_SIZE(uniphier_ld4_functions),
+       .caps = 0,
 };
 
-static int ph1_ld4_pinctrl_probe(struct platform_device *pdev)
+static int uniphier_ld4_pinctrl_probe(struct platform_device *pdev)
 {
-       return uniphier_pinctrl_probe(pdev, &ph1_ld4_pinctrl_desc,
-                                     &ph1_ld4_pindata);
+       return uniphier_pinctrl_probe(pdev, &uniphier_ld4_pindata);
 }
 
-static const struct of_device_id ph1_ld4_pinctrl_match[] = {
+static const struct of_device_id uniphier_ld4_pinctrl_match[] = {
+       { .compatible = "socionext,uniphier-ld4-pinctrl" },
        { .compatible = "socionext,ph1-ld4-pinctrl" },
        { /* sentinel */ }
 };
-MODULE_DEVICE_TABLE(of, ph1_ld4_pinctrl_match);
+MODULE_DEVICE_TABLE(of, uniphier_ld4_pinctrl_match);
 
-static struct platform_driver ph1_ld4_pinctrl_driver = {
-       .probe = ph1_ld4_pinctrl_probe,
+static struct platform_driver uniphier_ld4_pinctrl_driver = {
+       .probe = uniphier_ld4_pinctrl_probe,
        .driver = {
-               .name = DRIVER_NAME,
-               .of_match_table = ph1_ld4_pinctrl_match,
+               .name = "uniphier-ld4-pinctrl",
+               .of_match_table = uniphier_ld4_pinctrl_match,
        },
 };
-module_platform_driver(ph1_ld4_pinctrl_driver);
+module_platform_driver(uniphier_ld4_pinctrl_driver);
 
 MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
 MODULE_DESCRIPTION("UniPhier PH1-LD4 pinctrl driver");
index 150d339..708e510 100644 (file)
 
 #include "pinctrl-uniphier.h"
 
-#define DRIVER_NAME "ph1-ld6b-pinctrl"
-
-static const struct pinctrl_pin_desc ph1_ld6b_pins[] = {
+static const struct pinctrl_pin_desc uniphier_ld6b_pins[] = {
        UNIPHIER_PINCTRL_PIN(0, "ED0", UNIPHIER_PIN_IECTRL_NONE,
-                            0, UNIPHIER_PIN_DRV_4_8,
+                            0, UNIPHIER_PIN_DRV_1BIT,
                             0, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(1, "ED1", UNIPHIER_PIN_IECTRL_NONE,
-                            1, UNIPHIER_PIN_DRV_4_8,
+                            1, UNIPHIER_PIN_DRV_1BIT,
                             1, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(2, "ED2", UNIPHIER_PIN_IECTRL_NONE,
-                            2, UNIPHIER_PIN_DRV_4_8,
+                            2, UNIPHIER_PIN_DRV_1BIT,
                             2, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(3, "ED3", UNIPHIER_PIN_IECTRL_NONE,
-                            3, UNIPHIER_PIN_DRV_4_8,
+                            3, UNIPHIER_PIN_DRV_1BIT,
                             3, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(4, "ED4", UNIPHIER_PIN_IECTRL_NONE,
-                            4, UNIPHIER_PIN_DRV_4_8,
+                            4, UNIPHIER_PIN_DRV_1BIT,
                             4, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(5, "ED5", UNIPHIER_PIN_IECTRL_NONE,
-                            5, UNIPHIER_PIN_DRV_4_8,
+                            5, UNIPHIER_PIN_DRV_1BIT,
                             5, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(6, "ED6", UNIPHIER_PIN_IECTRL_NONE,
-                            6, UNIPHIER_PIN_DRV_4_8,
+                            6, UNIPHIER_PIN_DRV_1BIT,
                             6, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(7, "ED7", UNIPHIER_PIN_IECTRL_NONE,
-                            7, UNIPHIER_PIN_DRV_4_8,
+                            7, UNIPHIER_PIN_DRV_1BIT,
                             7, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(8, "XERWE0", UNIPHIER_PIN_IECTRL_NONE,
-                            8, UNIPHIER_PIN_DRV_4_8,
+                            8, UNIPHIER_PIN_DRV_1BIT,
                             8, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(9, "XERWE1", UNIPHIER_PIN_IECTRL_NONE,
-                            9, UNIPHIER_PIN_DRV_4_8,
+                            9, UNIPHIER_PIN_DRV_1BIT,
                             9, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(10, "ERXW", UNIPHIER_PIN_IECTRL_NONE,
-                            10, UNIPHIER_PIN_DRV_4_8,
+                            10, UNIPHIER_PIN_DRV_1BIT,
                             10, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(11, "ES0", UNIPHIER_PIN_IECTRL_NONE,
-                            11, UNIPHIER_PIN_DRV_4_8,
+                            11, UNIPHIER_PIN_DRV_1BIT,
                             11, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(12, "ES1", UNIPHIER_PIN_IECTRL_NONE,
-                            12, UNIPHIER_PIN_DRV_4_8,
+                            12, UNIPHIER_PIN_DRV_1BIT,
                             12, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(13, "ES2", UNIPHIER_PIN_IECTRL_NONE,
-                            13, UNIPHIER_PIN_DRV_4_8,
+                            13, UNIPHIER_PIN_DRV_1BIT,
                             13, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(14, "XECS1", UNIPHIER_PIN_IECTRL_NONE,
-                            14, UNIPHIER_PIN_DRV_4_8,
+                            14, UNIPHIER_PIN_DRV_1BIT,
                             14, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(15, "PCA00", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             15, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(16, "PCA01", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             16, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(17, "PCA02", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             17, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(18, "PCA03", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             18, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(19, "PCA04", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             19, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(20, "PCA05", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             20, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(21, "PCA06", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             21, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(22, "PCA07", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             22, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(23, "PCA08", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             23, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(24, "PCA09", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             24, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(25, "PCA10", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             25, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(26, "PCA11", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             26, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(27, "PCA12", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             27, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(28, "PCA13", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             28, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(29, "PCA14", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             29, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(30, "XNFRE", UNIPHIER_PIN_IECTRL_NONE,
-                            30, UNIPHIER_PIN_DRV_4_8,
+                            30, UNIPHIER_PIN_DRV_1BIT,
                             30, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(31, "XNFWE", UNIPHIER_PIN_IECTRL_NONE,
-                            31, UNIPHIER_PIN_DRV_4_8,
+                            31, UNIPHIER_PIN_DRV_1BIT,
                             31, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(32, "NFALE", UNIPHIER_PIN_IECTRL_NONE,
-                            32, UNIPHIER_PIN_DRV_4_8,
+                            32, UNIPHIER_PIN_DRV_1BIT,
                             32, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(33, "NFCLE", UNIPHIER_PIN_IECTRL_NONE,
-                            33, UNIPHIER_PIN_DRV_4_8,
+                            33, UNIPHIER_PIN_DRV_1BIT,
                             33, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(34, "XNFWP", UNIPHIER_PIN_IECTRL_NONE,
-                            34, UNIPHIER_PIN_DRV_4_8,
+                            34, UNIPHIER_PIN_DRV_1BIT,
                             34, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(35, "XNFCE0", UNIPHIER_PIN_IECTRL_NONE,
-                            35, UNIPHIER_PIN_DRV_4_8,
+                            35, UNIPHIER_PIN_DRV_1BIT,
                             35, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(36, "NFRYBY0", UNIPHIER_PIN_IECTRL_NONE,
-                            36, UNIPHIER_PIN_DRV_4_8,
+                            36, UNIPHIER_PIN_DRV_1BIT,
                             36, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(37, "XNFCE1", UNIPHIER_PIN_IECTRL_NONE,
-                            37, UNIPHIER_PIN_DRV_4_8,
+                            37, UNIPHIER_PIN_DRV_1BIT,
                             37, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(38, "NFRYBY1", UNIPHIER_PIN_IECTRL_NONE,
-                            38, UNIPHIER_PIN_DRV_4_8,
+                            38, UNIPHIER_PIN_DRV_1BIT,
                             38, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(39, "NFD0", UNIPHIER_PIN_IECTRL_NONE,
-                            39, UNIPHIER_PIN_DRV_4_8,
+                            39, UNIPHIER_PIN_DRV_1BIT,
                             39, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(40, "NFD1", UNIPHIER_PIN_IECTRL_NONE,
-                            40, UNIPHIER_PIN_DRV_4_8,
+                            40, UNIPHIER_PIN_DRV_1BIT,
                             40, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(41, "NFD2", UNIPHIER_PIN_IECTRL_NONE,
-                            41, UNIPHIER_PIN_DRV_4_8,
+                            41, UNIPHIER_PIN_DRV_1BIT,
                             41, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(42, "NFD3", UNIPHIER_PIN_IECTRL_NONE,
-                            42, UNIPHIER_PIN_DRV_4_8,
+                            42, UNIPHIER_PIN_DRV_1BIT,
                             42, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(43, "NFD4", UNIPHIER_PIN_IECTRL_NONE,
-                            43, UNIPHIER_PIN_DRV_4_8,
+                            43, UNIPHIER_PIN_DRV_1BIT,
                             43, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(44, "NFD5", UNIPHIER_PIN_IECTRL_NONE,
-                            44, UNIPHIER_PIN_DRV_4_8,
+                            44, UNIPHIER_PIN_DRV_1BIT,
                             44, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(45, "NFD6", UNIPHIER_PIN_IECTRL_NONE,
-                            45, UNIPHIER_PIN_DRV_4_8,
+                            45, UNIPHIER_PIN_DRV_1BIT,
                             45, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(46, "NFD7", UNIPHIER_PIN_IECTRL_NONE,
-                            46, UNIPHIER_PIN_DRV_4_8,
+                            46, UNIPHIER_PIN_DRV_1BIT,
                             46, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(47, "SDCLK", UNIPHIER_PIN_IECTRL_NONE,
-                            0, UNIPHIER_PIN_DRV_8_12_16_20,
+                            0, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(48, "SDCMD", UNIPHIER_PIN_IECTRL_NONE,
-                            4, UNIPHIER_PIN_DRV_8_12_16_20,
+                            1, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(49, "SDDAT0", UNIPHIER_PIN_IECTRL_NONE,
-                            8, UNIPHIER_PIN_DRV_8_12_16_20,
+                            2, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(50, "SDDAT1", UNIPHIER_PIN_IECTRL_NONE,
-                            12, UNIPHIER_PIN_DRV_8_12_16_20,
+                            3, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(51, "SDDAT2", UNIPHIER_PIN_IECTRL_NONE,
-                            16, UNIPHIER_PIN_DRV_8_12_16_20,
+                            4, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(52, "SDDAT3", UNIPHIER_PIN_IECTRL_NONE,
-                            20, UNIPHIER_PIN_DRV_8_12_16_20,
+                            5, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(53, "SDCD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             53, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(54, "SDWP", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             54, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(55, "SDVOLC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             55, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(56, "USB0VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             56, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(57, "USB0OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             57, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(58, "USB1VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             58, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(59, "USB1OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             59, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(60, "USB2VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             60, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(61, "USB2OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             61, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(62, "USB3VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             62, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(63, "USB3OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             63, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(64, "HS0BCLKOUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             64, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(65, "HS0SYNCOUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             65, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(66, "HS0VALOUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             66, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(67, "HS0DOUT0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             67, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(68, "HS0DOUT1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             68, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(69, "HS0DOUT2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             69, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(70, "HS0DOUT3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             70, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(71, "HS0DOUT4", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             71, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(72, "HS0DOUT5", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             72, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(73, "HS0DOUT6", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             73, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(74, "HS0DOUT7", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             74, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(75, "HS1BCLKIN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             75, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(76, "HS1SYNCIN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             76, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(77, "HS1VALIN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             77, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(78, "HS1DIN0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             78, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(79, "HS1DIN1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             79, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(80, "HS1DIN2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             80, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(81, "HS1DIN3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             81, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(82, "HS1DIN4", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             82, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(83, "HS1DIN5", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             83, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(84, "HS1DIN6", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             84, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(85, "HS1DIN7", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             85, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(86, "HS2BCLKIN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             86, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(87, "HS2SYNCIN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             87, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(88, "HS2VALIN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             88, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(89, "HS2DIN0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             89, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(90, "HS2DIN1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             90, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(91, "HS2DIN2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             91, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(92, "HS2DIN3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             92, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(93, "HS2DIN4", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             93, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(94, "HS2DIN5", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             94, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(95, "HS2DIN6", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             95, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(96, "HS2DIN7", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             96, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(97, "AO1IEC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             97, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(98, "AO1DACCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             98, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(99, "AO1BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             99, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(100, "AO1LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             100, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(101, "AO1D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             101, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(102, "AO1D1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             102, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(103, "AO1D2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             103, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(104, "AO1D3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             104, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(105, "AO2DACCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             105, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(106, "AO2BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             106, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(107, "AO2LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             107, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(108, "AO2D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             108, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(109, "SDA0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             109, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(110, "SCL0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             110, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(111, "SDA1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             111, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(112, "SCL1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             112, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(113, "SBO0", 0,
-                            113, UNIPHIER_PIN_DRV_4_8,
+                            113, UNIPHIER_PIN_DRV_1BIT,
                             113, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(114, "SBI0", 0,
-                            114, UNIPHIER_PIN_DRV_4_8,
+                            114, UNIPHIER_PIN_DRV_1BIT,
                             114, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(115, "TXD1", 0,
-                            115, UNIPHIER_PIN_DRV_4_8,
+                            115, UNIPHIER_PIN_DRV_1BIT,
                             115, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(116, "RXD1", 0,
-                            116, UNIPHIER_PIN_DRV_4_8,
+                            116, UNIPHIER_PIN_DRV_1BIT,
                             116, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(117, "PWSRA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             117, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(118, "XIRQ0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             118, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(119, "XIRQ1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             119, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(120, "XIRQ2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             120, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(121, "XIRQ3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             121, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(122, "XIRQ4", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             122, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(123, "XIRQ5", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             123, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(124, "XIRQ6", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             124, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(125, "XIRQ7", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             125, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(126, "XIRQ8", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             126, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(127, "PORT00", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             127, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(128, "PORT01", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             128, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(129, "PORT02", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             129, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(130, "PORT03", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             130, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(131, "PORT04", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             131, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(132, "PORT05", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             132, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(133, "PORT06", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             133, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(134, "PORT07", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             134, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(135, "PORT10", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             135, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(136, "PORT11", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             136, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(137, "PORT12", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             137, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(138, "PORT13", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             138, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(139, "PORT14", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             139, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(140, "PORT15", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             140, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(141, "PORT16", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             141, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(142, "LPST", UNIPHIER_PIN_IECTRL_NONE,
-                            142, UNIPHIER_PIN_DRV_4_8,
+                            142, UNIPHIER_PIN_DRV_1BIT,
                             142, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(143, "MDC", 0,
-                            143, UNIPHIER_PIN_DRV_4_8,
+                            143, UNIPHIER_PIN_DRV_1BIT,
                             143, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(144, "MDIO", 0,
-                            144, UNIPHIER_PIN_DRV_4_8,
+                            144, UNIPHIER_PIN_DRV_1BIT,
                             144, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(145, "MDIO_INTL", 0,
-                            145, UNIPHIER_PIN_DRV_4_8,
+                            145, UNIPHIER_PIN_DRV_1BIT,
                             145, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(146, "PHYRSTL", 0,
-                            146, UNIPHIER_PIN_DRV_4_8,
+                            146, UNIPHIER_PIN_DRV_1BIT,
                             146, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(147, "RGMII_RXCLK", 0,
-                            147, UNIPHIER_PIN_DRV_4_8,
+                            147, UNIPHIER_PIN_DRV_1BIT,
                             147, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(148, "RGMII_RXD0", 0,
-                            148, UNIPHIER_PIN_DRV_4_8,
+                            148, UNIPHIER_PIN_DRV_1BIT,
                             148, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(149, "RGMII_RXD1", 0,
-                            149, UNIPHIER_PIN_DRV_4_8,
+                            149, UNIPHIER_PIN_DRV_1BIT,
                             149, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(150, "RGMII_RXD2", 0,
-                            150, UNIPHIER_PIN_DRV_4_8,
+                            150, UNIPHIER_PIN_DRV_1BIT,
                             150, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(151, "RGMII_RXD3", 0,
-                            151, UNIPHIER_PIN_DRV_4_8,
+                            151, UNIPHIER_PIN_DRV_1BIT,
                             151, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(152, "RGMII_RXCTL", 0,
-                            152, UNIPHIER_PIN_DRV_4_8,
+                            152, UNIPHIER_PIN_DRV_1BIT,
                             152, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(153, "RGMII_TXCLK", 0,
-                            153, UNIPHIER_PIN_DRV_4_8,
+                            153, UNIPHIER_PIN_DRV_1BIT,
                             153, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(154, "RGMII_TXD0", 0,
-                            154, UNIPHIER_PIN_DRV_4_8,
+                            154, UNIPHIER_PIN_DRV_1BIT,
                             154, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(155, "RGMII_TXD1", 0,
-                            155, UNIPHIER_PIN_DRV_4_8,
+                            155, UNIPHIER_PIN_DRV_1BIT,
                             155, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(156, "RGMII_TXD2", 0,
-                            156, UNIPHIER_PIN_DRV_4_8,
+                            156, UNIPHIER_PIN_DRV_1BIT,
                             156, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(157, "RGMII_TXD3", 0,
-                            157, UNIPHIER_PIN_DRV_4_8,
+                            157, UNIPHIER_PIN_DRV_1BIT,
                             157, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(158, "RGMII_TXCTL", 0,
-                            158, UNIPHIER_PIN_DRV_4_8,
+                            158, UNIPHIER_PIN_DRV_1BIT,
                             158, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(159, "A_D_PCD00OUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             159, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(160, "A_D_PCD01OUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             160, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(161, "A_D_PCD02OUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             161, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(162, "A_D_PCD03OUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             162, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(163, "A_D_PCD04OUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             163, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(164, "A_D_PCD05OUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             164, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(165, "A_D_PCD06OUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             165, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(166, "A_D_PCD07OUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             166, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(167, "A_D_PCD00IN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             167, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(168, "A_D_PCD01IN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             168, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(169, "A_D_PCD02IN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             169, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(170, "A_D_PCD03IN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             170, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(171, "A_D_PCD04IN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             171, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(172, "A_D_PCD05IN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             172, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(173, "A_D_PCD06IN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             173, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(174, "A_D_PCD07IN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             174, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(175, "A_D_PCDNOE", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             175, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(176, "A_D_PC0READY", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             176, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(177, "A_D_PC0CD1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             177, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(178, "A_D_PC0CD2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             178, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(179, "A_D_PC0WAIT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             179, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(180, "A_D_PC0RESET", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             180, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(181, "A_D_PC0CE1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             181, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(182, "A_D_PC0WE", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             182, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(183, "A_D_PC0OE", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             183, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(184, "A_D_PC0IOWR", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             184, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(185, "A_D_PC0IORD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             185, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(186, "A_D_PC0NOE", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             186, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(187, "A_D_HS0BCLKIN", 0,
-                            187, UNIPHIER_PIN_DRV_4_8,
+                            187, UNIPHIER_PIN_DRV_1BIT,
                             187, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(188, "A_D_HS0SYNCIN", 0,
-                            188, UNIPHIER_PIN_DRV_4_8,
+                            188, UNIPHIER_PIN_DRV_1BIT,
                             188, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(189, "A_D_HS0VALIN", 0,
-                            189, UNIPHIER_PIN_DRV_4_8,
+                            189, UNIPHIER_PIN_DRV_1BIT,
                             189, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(190, "A_D_HS0DIN0", 0,
-                            190, UNIPHIER_PIN_DRV_4_8,
+                            190, UNIPHIER_PIN_DRV_1BIT,
                             190, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(191, "A_D_HS0DIN1", 0,
-                            191, UNIPHIER_PIN_DRV_4_8,
+                            191, UNIPHIER_PIN_DRV_1BIT,
                             191, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(192, "A_D_HS0DIN2", 0,
-                            192, UNIPHIER_PIN_DRV_4_8,
+                            192, UNIPHIER_PIN_DRV_1BIT,
                             192, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(193, "A_D_HS0DIN3", 0,
-                            193, UNIPHIER_PIN_DRV_4_8,
+                            193, UNIPHIER_PIN_DRV_1BIT,
                             193, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(194, "A_D_HS0DIN4", 0,
-                            194, UNIPHIER_PIN_DRV_4_8,
+                            194, UNIPHIER_PIN_DRV_1BIT,
                             194, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(195, "A_D_HS0DIN5", 0,
-                            195, UNIPHIER_PIN_DRV_4_8,
+                            195, UNIPHIER_PIN_DRV_1BIT,
                             195, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(196, "A_D_HS0DIN6", 0,
-                            196, UNIPHIER_PIN_DRV_4_8,
+                            196, UNIPHIER_PIN_DRV_1BIT,
                             196, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(197, "A_D_HS0DIN7", 0,
-                            197, UNIPHIER_PIN_DRV_4_8,
+                            197, UNIPHIER_PIN_DRV_1BIT,
                             197, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(198, "A_D_AO1ARC", 0,
-                            198, UNIPHIER_PIN_DRV_4_8,
+                            198, UNIPHIER_PIN_DRV_1BIT,
                             198, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(199, "A_D_SPIXRST", UNIPHIER_PIN_IECTRL_NONE,
-                            199, UNIPHIER_PIN_DRV_4_8,
+                            199, UNIPHIER_PIN_DRV_1BIT,
                             199, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(200, "A_D_SPISCLK0", UNIPHIER_PIN_IECTRL_NONE,
-                            200, UNIPHIER_PIN_DRV_4_8,
+                            200, UNIPHIER_PIN_DRV_1BIT,
                             200, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(201, "A_D_SPITXD0", UNIPHIER_PIN_IECTRL_NONE,
-                            201, UNIPHIER_PIN_DRV_4_8,
+                            201, UNIPHIER_PIN_DRV_1BIT,
                             201, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(202, "A_D_SPIRXD0", UNIPHIER_PIN_IECTRL_NONE,
-                            202, UNIPHIER_PIN_DRV_4_8,
+                            202, UNIPHIER_PIN_DRV_1BIT,
                             202, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(203, "A_D_DMDCLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             203, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(204, "A_D_DMDPSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             204, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(205, "A_D_DMDVAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             205, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(206, "A_D_DMDDATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             206, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(207, "A_D_HDMIRXXIRQ", 0,
-                            207, UNIPHIER_PIN_DRV_4_8,
+                            207, UNIPHIER_PIN_DRV_1BIT,
                             207, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(208, "A_D_VBIXIRQ", 0,
-                            208, UNIPHIER_PIN_DRV_4_8,
+                            208, UNIPHIER_PIN_DRV_1BIT,
                             208, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(209, "A_D_HDMITXXIRQ", 0,
-                            209, UNIPHIER_PIN_DRV_4_8,
+                            209, UNIPHIER_PIN_DRV_1BIT,
                             209, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(210, "A_D_DMDIRQ", UNIPHIER_PIN_IECTRL_NONE,
-                            210, UNIPHIER_PIN_DRV_4_8,
+                            210, UNIPHIER_PIN_DRV_1BIT,
                             210, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(211, "A_D_SPICIRQ", UNIPHIER_PIN_IECTRL_NONE,
-                            211, UNIPHIER_PIN_DRV_4_8,
+                            211, UNIPHIER_PIN_DRV_1BIT,
                             211, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(212, "A_D_SPIBIRQ", UNIPHIER_PIN_IECTRL_NONE,
-                            212, UNIPHIER_PIN_DRV_4_8,
+                            212, UNIPHIER_PIN_DRV_1BIT,
                             212, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(213, "A_D_BESDAOUT", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             213, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(214, "A_D_BESDAIN", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             214, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(215, "A_D_BESCLOUT", UNIPHIER_PIN_IECTRL_NONE,
-                            215, UNIPHIER_PIN_DRV_4_8,
+                            215, UNIPHIER_PIN_DRV_1BIT,
                             215, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(216, "A_D_VDACCLKOUT", 0,
-                            216, UNIPHIER_PIN_DRV_4_8,
+                            216, UNIPHIER_PIN_DRV_1BIT,
                             216, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(217, "A_D_VDACDOUT5", 0,
-                            217, UNIPHIER_PIN_DRV_4_8,
+                            217, UNIPHIER_PIN_DRV_1BIT,
                             217, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(218, "A_D_VDACDOUT6", 0,
-                            218, UNIPHIER_PIN_DRV_4_8,
+                            218, UNIPHIER_PIN_DRV_1BIT,
                             218, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(219, "A_D_VDACDOUT7", 0,
-                            219, UNIPHIER_PIN_DRV_4_8,
+                            219, UNIPHIER_PIN_DRV_1BIT,
                             219, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(220, "A_D_VDACDOUT8", 0,
-                            220, UNIPHIER_PIN_DRV_4_8,
+                            220, UNIPHIER_PIN_DRV_1BIT,
                             220, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(221, "A_D_VDACDOUT9", 0,
-                            221, UNIPHIER_PIN_DRV_4_8,
+                            221, UNIPHIER_PIN_DRV_1BIT,
                             221, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(222, "A_D_SIFBCKIN", 0,
-                            222, UNIPHIER_PIN_DRV_4_8,
+                            222, UNIPHIER_PIN_DRV_1BIT,
                             222, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(223, "A_D_SIFLRCKIN", 0,
-                            223, UNIPHIER_PIN_DRV_4_8,
+                            223, UNIPHIER_PIN_DRV_1BIT,
                             223, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(224, "A_D_SIFDIN", 0,
-                            224, UNIPHIER_PIN_DRV_4_8,
+                            224, UNIPHIER_PIN_DRV_1BIT,
                             224, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(225, "A_D_LIBCKOUT", 0,
-                            225, UNIPHIER_PIN_DRV_4_8,
+                            225, UNIPHIER_PIN_DRV_1BIT,
                             225, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(226, "A_D_LILRCKOUT", 0,
-                            226, UNIPHIER_PIN_DRV_4_8,
+                            226, UNIPHIER_PIN_DRV_1BIT,
                             226, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(227, "A_D_LIDIN", 0,
-                            227, UNIPHIER_PIN_DRV_4_8,
+                            227, UNIPHIER_PIN_DRV_1BIT,
                             227, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(228, "A_D_LODOUT", 0,
-                            228, UNIPHIER_PIN_DRV_4_8,
+                            228, UNIPHIER_PIN_DRV_1BIT,
                             228, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(229, "A_D_HPDOUT", 0,
-                            229, UNIPHIER_PIN_DRV_4_8,
+                            229, UNIPHIER_PIN_DRV_1BIT,
                             229, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(230, "A_D_MCLK", 0,
-                            230, UNIPHIER_PIN_DRV_4_8,
+                            230, UNIPHIER_PIN_DRV_1BIT,
                             230, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(231, "A_D_A2PLLREFOUT", 0,
-                            231, UNIPHIER_PIN_DRV_4_8,
+                            231, UNIPHIER_PIN_DRV_1BIT,
                             231, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(232, "A_D_HDMI3DSDAOUT", 0,
-                            232, UNIPHIER_PIN_DRV_4_8,
+                            232, UNIPHIER_PIN_DRV_1BIT,
                             232, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(233, "A_D_HDMI3DSDAIN", 0,
-                            233, UNIPHIER_PIN_DRV_4_8,
+                            233, UNIPHIER_PIN_DRV_1BIT,
                             233, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(234, "A_D_HDMI3DSCLIN", 0,
-                            234, UNIPHIER_PIN_DRV_4_8,
+                            234, UNIPHIER_PIN_DRV_1BIT,
                             234, UNIPHIER_PIN_PULL_DOWN),
 };
 
@@ -737,52 +735,73 @@ static const unsigned adinter_pins[] = {
        215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228,
        229, 230, 231, 232, 233, 234,
 };
-static const unsigned adinter_muxvals[] = {
+static const int adinter_muxvals[] = {
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0,
 };
 static const unsigned emmc_pins[] = {36, 37, 38, 39, 40, 41, 42};
-static const unsigned emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1};
+static const int emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1};
 static const unsigned emmc_dat8_pins[] = {43, 44, 45, 46};
-static const unsigned emmc_dat8_muxvals[] = {1, 1, 1, 1};
+static const int emmc_dat8_muxvals[] = {1, 1, 1, 1};
+static const unsigned ether_rgmii_pins[] = {143, 144, 145, 146, 147, 148, 149,
+                                           150, 151, 152, 153, 154, 155, 156,
+                                           157, 158};
+static const int ether_rgmii_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                         0, 0, 0, 0};
+static const unsigned ether_rmii_pins[] = {143, 144, 145, 146, 147, 148, 149,
+                                          150, 152, 154, 155, 158};
+static const int ether_rmii_muxvals[] = {0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1};
 static const unsigned i2c0_pins[] = {109, 110};
-static const unsigned i2c0_muxvals[] = {0, 0};
+static const int i2c0_muxvals[] = {0, 0};
 static const unsigned i2c1_pins[] = {111, 112};
-static const unsigned i2c1_muxvals[] = {0, 0};
+static const int i2c1_muxvals[] = {0, 0};
 static const unsigned i2c2_pins[] = {115, 116};
-static const unsigned i2c2_muxvals[] = {1, 1};
+static const int i2c2_muxvals[] = {1, 1};
 static const unsigned i2c3_pins[] = {118, 119};
-static const unsigned i2c3_muxvals[] = {1, 1};
+static const int i2c3_muxvals[] = {1, 1};
 static const unsigned nand_pins[] = {30, 31, 32, 33, 34, 35, 36, 39, 40, 41,
                                     42, 43, 44, 45, 46};
-static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                                       0, 0};
+static const int nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 static const unsigned nand_cs1_pins[] = {37, 38};
-static const unsigned nand_cs1_muxvals[] = {0, 0};
+static const int nand_cs1_muxvals[] = {0, 0};
 static const unsigned sd_pins[] = {47, 48, 49, 50, 51, 52, 53, 54, 55};
-static const unsigned sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const int sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned system_bus_pins[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+                                          11, 12, 13};
+static const int system_bus_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                        0};
+static const unsigned system_bus_cs1_pins[] = {14};
+static const int system_bus_cs1_muxvals[] = {0};
+static const unsigned system_bus_cs2_pins[] = {37};
+static const int system_bus_cs2_muxvals[] = {6};
+static const unsigned system_bus_cs3_pins[] = {38};
+static const int system_bus_cs3_muxvals[] = {6};
+static const unsigned system_bus_cs4_pins[] = {115};
+static const int system_bus_cs4_muxvals[] = {6};
+static const unsigned system_bus_cs5_pins[] = {55};
+static const int system_bus_cs5_muxvals[] = {6};
 static const unsigned uart0_pins[] = {135, 136};
-static const unsigned uart0_muxvals[] = {3, 3};
+static const int uart0_muxvals[] = {3, 3};
 static const unsigned uart0b_pins[] = {11, 12};
-static const unsigned uart0b_muxvals[] = {2, 2};
+static const int uart0b_muxvals[] = {2, 2};
 static const unsigned uart1_pins[] = {115, 116};
-static const unsigned uart1_muxvals[] = {0, 0};
+static const int uart1_muxvals[] = {0, 0};
 static const unsigned uart1b_pins[] = {113, 114};
-static const unsigned uart1b_muxvals[] = {1, 1};
+static const int uart1b_muxvals[] = {1, 1};
 static const unsigned uart2_pins[] = {113, 114};
-static const unsigned uart2_muxvals[] = {2, 2};
+static const int uart2_muxvals[] = {2, 2};
 static const unsigned uart2b_pins[] = {86, 87};
-static const unsigned uart2b_muxvals[] = {1, 1};
+static const int uart2b_muxvals[] = {1, 1};
 static const unsigned usb0_pins[] = {56, 57};
-static const unsigned usb0_muxvals[] = {0, 0};
+static const int usb0_muxvals[] = {0, 0};
 static const unsigned usb1_pins[] = {58, 59};
-static const unsigned usb1_muxvals[] = {0, 0};
+static const int usb1_muxvals[] = {0, 0};
 static const unsigned usb2_pins[] = {60, 61};
-static const unsigned usb2_muxvals[] = {0, 0};
+static const int usb2_muxvals[] = {0, 0};
 static const unsigned usb3_pins[] = {62, 63};
-static const unsigned usb3_muxvals[] = {0, 0};
+static const int usb3_muxvals[] = {0, 0};
 static const unsigned port_range0_pins[] = {
        127, 128, 129, 130, 131, 132, 133, 134,         /* PORT0x */
        135, 136, 137, 138, 139, 140, 141, 142,         /* PORT1x */
@@ -796,7 +815,7 @@ static const unsigned port_range0_pins[] = {
        61, 62, 63, 64, 65, 66, 67, 68,                 /* PORT9x */
        69, 70, 71, 76, 77, 78, 79, 80,                 /* PORT10x */
 };
-static const unsigned port_range0_muxvals[] = {
+static const int port_range0_muxvals[] = {
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT0x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT1x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT2x */
@@ -828,7 +847,7 @@ static const unsigned port_range1_pins[] = {
        218, 219, 220, 221, 223, 224, 225, 226,         /* PORT27x */
        227, 228, 229, 230, 231, 232, 233, 234,         /* PORT28x */
 };
-static const unsigned port_range1_muxvals[] = {
+static const int port_range1_muxvals[] = {
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT12x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT13x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT14x */
@@ -852,16 +871,18 @@ static const unsigned xirq_pins[] = {
        126, 72, 73, 92, 177, 93, 94, 176,              /* XIRQ8-15 */
        74, 91, 27, 28, 29, 75, 20, 26,                 /* XIRQ16-23 */
 };
-static const unsigned xirq_muxvals[] = {
+static const int xirq_muxvals[] = {
        14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ0-7 */
        14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ8-15 */
        14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ16-23 */
 };
 
-static const struct uniphier_pinctrl_group ph1_ld6b_groups[] = {
+static const struct uniphier_pinctrl_group uniphier_ld6b_groups[] = {
        UNIPHIER_PINCTRL_GROUP(adinter),
        UNIPHIER_PINCTRL_GROUP(emmc),
        UNIPHIER_PINCTRL_GROUP(emmc_dat8),
+       UNIPHIER_PINCTRL_GROUP(ether_rgmii),
+       UNIPHIER_PINCTRL_GROUP(ether_rmii),
        UNIPHIER_PINCTRL_GROUP(i2c0),
        UNIPHIER_PINCTRL_GROUP(i2c1),
        UNIPHIER_PINCTRL_GROUP(i2c2),
@@ -869,6 +890,12 @@ static const struct uniphier_pinctrl_group ph1_ld6b_groups[] = {
        UNIPHIER_PINCTRL_GROUP(nand),
        UNIPHIER_PINCTRL_GROUP(nand_cs1),
        UNIPHIER_PINCTRL_GROUP(sd),
+       UNIPHIER_PINCTRL_GROUP(system_bus),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs1),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs2),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs3),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs4),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs5),
        UNIPHIER_PINCTRL_GROUP(uart0),
        UNIPHIER_PINCTRL_GROUP(uart0b),
        UNIPHIER_PINCTRL_GROUP(uart1),
@@ -1134,12 +1161,20 @@ static const struct uniphier_pinctrl_group ph1_ld6b_groups[] = {
 
 static const char * const adinter_groups[] = {"adinter"};
 static const char * const emmc_groups[] = {"emmc", "emmc_dat8"};
+static const char * const ether_rgmii_groups[] = {"ether_rgmii"};
+static const char * const ether_rmii_groups[] = {"ether_rmii"};
 static const char * const i2c0_groups[] = {"i2c0"};
 static const char * const i2c1_groups[] = {"i2c1"};
 static const char * const i2c2_groups[] = {"i2c2"};
 static const char * const i2c3_groups[] = {"i2c3"};
 static const char * const nand_groups[] = {"nand", "nand_cs1"};
 static const char * const sd_groups[] = {"sd"};
+static const char * const system_bus_groups[] = {"system_bus",
+                                                "system_bus_cs1",
+                                                "system_bus_cs2",
+                                                "system_bus_cs3",
+                                                "system_bus_cs4",
+                                                "system_bus_cs5"};
 static const char * const uart0_groups[] = {"uart0", "uart0b"};
 static const char * const uart1_groups[] = {"uart1", "uart1b"};
 static const char * const uart2_groups[] = {"uart2", "uart2b"};
@@ -1215,15 +1250,18 @@ static const char * const xirq_groups[] = {
        "xirq20", "xirq21", "xirq22", "xirq23",
 };
 
-static const struct uniphier_pinmux_function ph1_ld6b_functions[] = {
+static const struct uniphier_pinmux_function uniphier_ld6b_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(adinter), /* Achip-Dchip interconnect */
        UNIPHIER_PINMUX_FUNCTION(emmc),
+       UNIPHIER_PINMUX_FUNCTION(ether_rgmii),
+       UNIPHIER_PINMUX_FUNCTION(ether_rmii),
        UNIPHIER_PINMUX_FUNCTION(i2c0),
        UNIPHIER_PINMUX_FUNCTION(i2c1),
        UNIPHIER_PINMUX_FUNCTION(i2c2),
        UNIPHIER_PINMUX_FUNCTION(i2c3),
        UNIPHIER_PINMUX_FUNCTION(nand),
        UNIPHIER_PINMUX_FUNCTION(sd),
+       UNIPHIER_PINMUX_FUNCTION(system_bus),
        UNIPHIER_PINMUX_FUNCTION(uart0),
        UNIPHIER_PINMUX_FUNCTION(uart1),
        UNIPHIER_PINMUX_FUNCTION(uart2),
@@ -1235,43 +1273,36 @@ static const struct uniphier_pinmux_function ph1_ld6b_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(xirq),
 };
 
-static struct uniphier_pinctrl_socdata ph1_ld6b_pindata = {
-       .groups = ph1_ld6b_groups,
-       .groups_count = ARRAY_SIZE(ph1_ld6b_groups),
-       .functions = ph1_ld6b_functions,
-       .functions_count = ARRAY_SIZE(ph1_ld6b_functions),
-       .mux_bits = 8,
-       .reg_stride = 4,
-       .load_pinctrl = false,
-};
-
-static struct pinctrl_desc ph1_ld6b_pinctrl_desc = {
-       .name = DRIVER_NAME,
-       .pins = ph1_ld6b_pins,
-       .npins = ARRAY_SIZE(ph1_ld6b_pins),
-       .owner = THIS_MODULE,
+static struct uniphier_pinctrl_socdata uniphier_ld6b_pindata = {
+       .pins = uniphier_ld6b_pins,
+       .npins = ARRAY_SIZE(uniphier_ld6b_pins),
+       .groups = uniphier_ld6b_groups,
+       .groups_count = ARRAY_SIZE(uniphier_ld6b_groups),
+       .functions = uniphier_ld6b_functions,
+       .functions_count = ARRAY_SIZE(uniphier_ld6b_functions),
+       .caps = 0,
 };
 
-static int ph1_ld6b_pinctrl_probe(struct platform_device *pdev)
+static int uniphier_ld6b_pinctrl_probe(struct platform_device *pdev)
 {
-       return uniphier_pinctrl_probe(pdev, &ph1_ld6b_pinctrl_desc,
-                                     &ph1_ld6b_pindata);
+       return uniphier_pinctrl_probe(pdev, &uniphier_ld6b_pindata);
 }
 
-static const struct of_device_id ph1_ld6b_pinctrl_match[] = {
+static const struct of_device_id uniphier_ld6b_pinctrl_match[] = {
+       { .compatible = "socionext,uniphier-ld6b-pinctrl" },
        { .compatible = "socionext,ph1-ld6b-pinctrl" },
        { /* sentinel */ }
 };
-MODULE_DEVICE_TABLE(of, ph1_ld6b_pinctrl_match);
+MODULE_DEVICE_TABLE(of, uniphier_ld6b_pinctrl_match);
 
-static struct platform_driver ph1_ld6b_pinctrl_driver = {
-       .probe = ph1_ld6b_pinctrl_probe,
+static struct platform_driver uniphier_ld6b_pinctrl_driver = {
+       .probe = uniphier_ld6b_pinctrl_probe,
        .driver = {
-               .name = DRIVER_NAME,
-               .of_match_table = ph1_ld6b_pinctrl_match,
+               .name = "uniphier-ld6b-pinctrl",
+               .of_match_table = uniphier_ld6b_pinctrl_match,
        },
 };
-module_platform_driver(ph1_ld6b_pinctrl_driver);
+module_platform_driver(uniphier_ld6b_pinctrl_driver);
 
 MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
 MODULE_DESCRIPTION("UniPhier PH1-LD6b pinctrl driver");
index b1f09e6..c306e84 100644 (file)
 
 #include "pinctrl-uniphier.h"
 
-#define DRIVER_NAME "ph1-pro4-pinctrl"
-
-static const struct pinctrl_pin_desc ph1_pro4_pins[] = {
+static const struct pinctrl_pin_desc uniphier_pro4_pins[] = {
        UNIPHIER_PINCTRL_PIN(0, "CK24O", UNIPHIER_PIN_IECTRL_NONE,
-                            0, UNIPHIER_PIN_DRV_4_8,
+                            0, UNIPHIER_PIN_DRV_1BIT,
                             0, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(1, "VC27A", UNIPHIER_PIN_IECTRL_NONE,
-                            1, UNIPHIER_PIN_DRV_4_8,
+                            1, UNIPHIER_PIN_DRV_1BIT,
                             1, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(2, "CK27AI", UNIPHIER_PIN_IECTRL_NONE,
-                            2, UNIPHIER_PIN_DRV_4_8,
+                            2, UNIPHIER_PIN_DRV_1BIT,
                             2, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(3, "CK27AO", UNIPHIER_PIN_IECTRL_NONE,
-                            3, UNIPHIER_PIN_DRV_4_8,
+                            3, UNIPHIER_PIN_DRV_1BIT,
                             3, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(4, "CKSEL", UNIPHIER_PIN_IECTRL_NONE,
-                            4, UNIPHIER_PIN_DRV_4_8,
+                            4, UNIPHIER_PIN_DRV_1BIT,
                             4, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(5, "CK27AV", UNIPHIER_PIN_IECTRL_NONE,
-                            5, UNIPHIER_PIN_DRV_4_8,
+                            5, UNIPHIER_PIN_DRV_1BIT,
                             5, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(6, "AEXCKA", UNIPHIER_PIN_IECTRL_NONE,
-                            6, UNIPHIER_PIN_DRV_4_8,
+                            6, UNIPHIER_PIN_DRV_1BIT,
                             6, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(7, "ASEL", UNIPHIER_PIN_IECTRL_NONE,
-                            7, UNIPHIER_PIN_DRV_4_8,
+                            7, UNIPHIER_PIN_DRV_1BIT,
                             7, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(8, "ARCRESET", UNIPHIER_PIN_IECTRL_NONE,
-                            8, UNIPHIER_PIN_DRV_4_8,
+                            8, UNIPHIER_PIN_DRV_1BIT,
                             8, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(9, "ARCUNLOCK", UNIPHIER_PIN_IECTRL_NONE,
-                            9, UNIPHIER_PIN_DRV_4_8,
+                            9, UNIPHIER_PIN_DRV_1BIT,
                             9, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(10, "XSRST", UNIPHIER_PIN_IECTRL_NONE,
-                            10, UNIPHIER_PIN_DRV_4_8,
+                            10, UNIPHIER_PIN_DRV_1BIT,
                             10, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(11, "XNMIRQ", UNIPHIER_PIN_IECTRL_NONE,
-                            11, UNIPHIER_PIN_DRV_4_8,
+                            11, UNIPHIER_PIN_DRV_1BIT,
                             11, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(12, "XSCIRQ", UNIPHIER_PIN_IECTRL_NONE,
-                            12, UNIPHIER_PIN_DRV_4_8,
+                            12, UNIPHIER_PIN_DRV_1BIT,
                             12, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(13, "EXTRG", UNIPHIER_PIN_IECTRL_NONE,
-                            13, UNIPHIER_PIN_DRV_4_8,
+                            13, UNIPHIER_PIN_DRV_1BIT,
                             13, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(14, "TRCCLK", UNIPHIER_PIN_IECTRL_NONE,
-                            14, UNIPHIER_PIN_DRV_4_8,
+                            14, UNIPHIER_PIN_DRV_1BIT,
                             14, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(15, "TRCCTL", UNIPHIER_PIN_IECTRL_NONE,
-                            15, UNIPHIER_PIN_DRV_4_8,
+                            15, UNIPHIER_PIN_DRV_1BIT,
                             15, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(16, "TRCD0", UNIPHIER_PIN_IECTRL_NONE,
-                            16, UNIPHIER_PIN_DRV_4_8,
+                            16, UNIPHIER_PIN_DRV_1BIT,
                             16, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(17, "TRCD1", UNIPHIER_PIN_IECTRL_NONE,
-                            17, UNIPHIER_PIN_DRV_4_8,
+                            17, UNIPHIER_PIN_DRV_1BIT,
                             17, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(18, "TRCD2", UNIPHIER_PIN_IECTRL_NONE,
-                            18, UNIPHIER_PIN_DRV_4_8,
+                            18, UNIPHIER_PIN_DRV_1BIT,
                             18, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(19, "TRCD3", UNIPHIER_PIN_IECTRL_NONE,
-                            19, UNIPHIER_PIN_DRV_4_8,
+                            19, UNIPHIER_PIN_DRV_1BIT,
                             19, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(20, "TRCD4", UNIPHIER_PIN_IECTRL_NONE,
-                            20, UNIPHIER_PIN_DRV_4_8,
+                            20, UNIPHIER_PIN_DRV_1BIT,
                             20, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(21, "TRCD5", UNIPHIER_PIN_IECTRL_NONE,
-                            21, UNIPHIER_PIN_DRV_4_8,
+                            21, UNIPHIER_PIN_DRV_1BIT,
                             21, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(22, "TRCD6", UNIPHIER_PIN_IECTRL_NONE,
-                            22, UNIPHIER_PIN_DRV_4_8,
+                            22, UNIPHIER_PIN_DRV_1BIT,
                             22, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(23, "TRCD7", UNIPHIER_PIN_IECTRL_NONE,
-                            23, UNIPHIER_PIN_DRV_4_8,
+                            23, UNIPHIER_PIN_DRV_1BIT,
                             23, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(24, "XECS1", UNIPHIER_PIN_IECTRL_NONE,
-                            24, UNIPHIER_PIN_DRV_4_8,
+                            24, UNIPHIER_PIN_DRV_1BIT,
                             24, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(25, "ERXW", UNIPHIER_PIN_IECTRL_NONE,
-                            25, UNIPHIER_PIN_DRV_4_8,
+                            25, UNIPHIER_PIN_DRV_1BIT,
                             25, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(26, "XERWE0", UNIPHIER_PIN_IECTRL_NONE,
-                            26, UNIPHIER_PIN_DRV_4_8,
+                            26, UNIPHIER_PIN_DRV_1BIT,
                             26, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(27, "XERWE1", UNIPHIER_PIN_IECTRL_NONE,
-                            27, UNIPHIER_PIN_DRV_4_8,
+                            27, UNIPHIER_PIN_DRV_1BIT,
                             27, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(28, "ES0", UNIPHIER_PIN_IECTRL_NONE,
-                            28, UNIPHIER_PIN_DRV_4_8,
+                            28, UNIPHIER_PIN_DRV_1BIT,
                             28, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(29, "ES1", UNIPHIER_PIN_IECTRL_NONE,
-                            29, UNIPHIER_PIN_DRV_4_8,
+                            29, UNIPHIER_PIN_DRV_1BIT,
                             29, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(30, "ES2", UNIPHIER_PIN_IECTRL_NONE,
-                            30, UNIPHIER_PIN_DRV_4_8,
+                            30, UNIPHIER_PIN_DRV_1BIT,
                             30, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(31, "ED0", UNIPHIER_PIN_IECTRL_NONE,
-                            31, UNIPHIER_PIN_DRV_4_8,
+                            31, UNIPHIER_PIN_DRV_1BIT,
                             31, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(32, "ED1", UNIPHIER_PIN_IECTRL_NONE,
-                            32, UNIPHIER_PIN_DRV_4_8,
+                            32, UNIPHIER_PIN_DRV_1BIT,
                             32, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(33, "ED2", UNIPHIER_PIN_IECTRL_NONE,
-                            33, UNIPHIER_PIN_DRV_4_8,
+                            33, UNIPHIER_PIN_DRV_1BIT,
                             33, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(34, "ED3", UNIPHIER_PIN_IECTRL_NONE,
-                            34, UNIPHIER_PIN_DRV_4_8,
+                            34, UNIPHIER_PIN_DRV_1BIT,
                             34, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(35, "ED4", UNIPHIER_PIN_IECTRL_NONE,
-                            35, UNIPHIER_PIN_DRV_4_8,
+                            35, UNIPHIER_PIN_DRV_1BIT,
                             35, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(36, "ED5", UNIPHIER_PIN_IECTRL_NONE,
-                            36, UNIPHIER_PIN_DRV_4_8,
+                            36, UNIPHIER_PIN_DRV_1BIT,
                             36, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(37, "ED6", UNIPHIER_PIN_IECTRL_NONE,
-                            37, UNIPHIER_PIN_DRV_4_8,
+                            37, UNIPHIER_PIN_DRV_1BIT,
                             37, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(38, "ED7", UNIPHIER_PIN_IECTRL_NONE,
-                            38, UNIPHIER_PIN_DRV_4_8,
+                            38, UNIPHIER_PIN_DRV_1BIT,
                             38, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(39, "BOOTSWAP", UNIPHIER_PIN_IECTRL_NONE,
-                            39, UNIPHIER_PIN_DRV_NONE,
+                            -1, UNIPHIER_PIN_DRV_NONE,
                             39, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(40, "NFD0", UNIPHIER_PIN_IECTRL_NONE,
-                            2, UNIPHIER_PIN_DRV_8_12_16_20,
+                            2, UNIPHIER_PIN_DRV_2BIT,
                             40, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(41, "NFD1", UNIPHIER_PIN_IECTRL_NONE,
-                            3, UNIPHIER_PIN_DRV_8_12_16_20,
+                            3, UNIPHIER_PIN_DRV_2BIT,
                             41, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(42, "NFD2", UNIPHIER_PIN_IECTRL_NONE,
-                            4, UNIPHIER_PIN_DRV_8_12_16_20,
+                            4, UNIPHIER_PIN_DRV_2BIT,
                             42, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(43, "NFD3", UNIPHIER_PIN_IECTRL_NONE,
-                            5, UNIPHIER_PIN_DRV_8_12_16_20,
+                            5, UNIPHIER_PIN_DRV_2BIT,
                             43, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(44, "NFD4", UNIPHIER_PIN_IECTRL_NONE,
-                            6, UNIPHIER_PIN_DRV_8_12_16_20,
+                            6, UNIPHIER_PIN_DRV_2BIT,
                             44, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(45, "NFD5", UNIPHIER_PIN_IECTRL_NONE,
-                            7, UNIPHIER_PIN_DRV_8_12_16_20,
+                            7, UNIPHIER_PIN_DRV_2BIT,
                             45, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(46, "NFD6", UNIPHIER_PIN_IECTRL_NONE,
-                            8, UNIPHIER_PIN_DRV_8_12_16_20,
+                            8, UNIPHIER_PIN_DRV_2BIT,
                             46, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(47, "NFD7", UNIPHIER_PIN_IECTRL_NONE,
-                            9, UNIPHIER_PIN_DRV_8_12_16_20,
+                            9, UNIPHIER_PIN_DRV_2BIT,
                             47, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(48, "NFALE", UNIPHIER_PIN_IECTRL_NONE,
-                            48, UNIPHIER_PIN_DRV_4_8,
+                            48, UNIPHIER_PIN_DRV_1BIT,
                             48, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(49, "NFCLE", UNIPHIER_PIN_IECTRL_NONE,
-                            49, UNIPHIER_PIN_DRV_4_8,
+                            49, UNIPHIER_PIN_DRV_1BIT,
                             49, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(50, "XNFRE", UNIPHIER_PIN_IECTRL_NONE,
-                            50, UNIPHIER_PIN_DRV_4_8,
+                            50, UNIPHIER_PIN_DRV_1BIT,
                             50, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(51, "XNFWE", UNIPHIER_PIN_IECTRL_NONE,
-                            0, UNIPHIER_PIN_DRV_8_12_16_20,
+                            0, UNIPHIER_PIN_DRV_2BIT,
                             51, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(52, "XNFWP", UNIPHIER_PIN_IECTRL_NONE,
-                            52, UNIPHIER_PIN_DRV_4_8,
+                            52, UNIPHIER_PIN_DRV_1BIT,
                             52, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(53, "XNFCE0", UNIPHIER_PIN_IECTRL_NONE,
-                            1, UNIPHIER_PIN_DRV_8_12_16_20,
+                            1, UNIPHIER_PIN_DRV_2BIT,
                             53, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(54, "NRYBY0", UNIPHIER_PIN_IECTRL_NONE,
-                            54, UNIPHIER_PIN_DRV_4_8,
+                            54, UNIPHIER_PIN_DRV_1BIT,
                             54, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(55, "DMDSCLTST", UNIPHIER_PIN_IECTRL_NONE,
                             -1, UNIPHIER_PIN_DRV_NONE,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(56, "DMDSDATST", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(57, "AGCI0", 3,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             55, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(58, "DMDSCL0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(59, "DMDSDA0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(60, "AGCBS0", 5,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             56, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(61, "DMDSCL1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(62, "DMDSDA1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(63, "ANTSHORT", UNIPHIER_PIN_IECTRL_NONE,
-                            57, UNIPHIER_PIN_DRV_4_8,
+                            57, UNIPHIER_PIN_DRV_1BIT,
                             57, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(64, "CH0CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            58, UNIPHIER_PIN_DRV_4_8,
+                            58, UNIPHIER_PIN_DRV_1BIT,
                             58, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(65, "CH0VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            59, UNIPHIER_PIN_DRV_4_8,
+                            59, UNIPHIER_PIN_DRV_1BIT,
                             59, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(66, "CH0PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            60, UNIPHIER_PIN_DRV_4_8,
+                            60, UNIPHIER_PIN_DRV_1BIT,
                             60, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(67, "CH0DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            61, UNIPHIER_PIN_DRV_4_8,
+                            61, UNIPHIER_PIN_DRV_1BIT,
                             61, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(68, "CH1CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            62, UNIPHIER_PIN_DRV_4_8,
+                            62, UNIPHIER_PIN_DRV_1BIT,
                             62, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(69, "CH1VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            63, UNIPHIER_PIN_DRV_4_8,
+                            63, UNIPHIER_PIN_DRV_1BIT,
                             63, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(70, "CH1PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            64, UNIPHIER_PIN_DRV_4_8,
+                            64, UNIPHIER_PIN_DRV_1BIT,
                             64, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(71, "CH1DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            65, UNIPHIER_PIN_DRV_4_8,
+                            65, UNIPHIER_PIN_DRV_1BIT,
                             65, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(72, "CH2CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            66, UNIPHIER_PIN_DRV_4_8,
+                            66, UNIPHIER_PIN_DRV_1BIT,
                             66, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(73, "CH2VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            67, UNIPHIER_PIN_DRV_4_8,
+                            67, UNIPHIER_PIN_DRV_1BIT,
                             67, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(74, "CH2PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            68, UNIPHIER_PIN_DRV_4_8,
+                            68, UNIPHIER_PIN_DRV_1BIT,
                             68, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(75, "CH2DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            69, UNIPHIER_PIN_DRV_4_8,
+                            69, UNIPHIER_PIN_DRV_1BIT,
                             69, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(76, "CH3CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            70, UNIPHIER_PIN_DRV_4_8,
+                            70, UNIPHIER_PIN_DRV_1BIT,
                             70, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(77, "CH3VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            71, UNIPHIER_PIN_DRV_4_8,
+                            71, UNIPHIER_PIN_DRV_1BIT,
                             71, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(78, "CH3PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            72, UNIPHIER_PIN_DRV_4_8,
+                            72, UNIPHIER_PIN_DRV_1BIT,
                             72, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(79, "CH3DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            73, UNIPHIER_PIN_DRV_4_8,
+                            73, UNIPHIER_PIN_DRV_1BIT,
                             73, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(80, "CH4CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            74, UNIPHIER_PIN_DRV_4_8,
+                            74, UNIPHIER_PIN_DRV_1BIT,
                             74, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(81, "CH4VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            75, UNIPHIER_PIN_DRV_4_8,
+                            75, UNIPHIER_PIN_DRV_1BIT,
                             75, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(82, "CH4PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            76, UNIPHIER_PIN_DRV_4_8,
+                            76, UNIPHIER_PIN_DRV_1BIT,
                             76, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(83, "CH4DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            77, UNIPHIER_PIN_DRV_4_8,
+                            77, UNIPHIER_PIN_DRV_1BIT,
                             77, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(84, "CH5CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            78, UNIPHIER_PIN_DRV_4_8,
+                            78, UNIPHIER_PIN_DRV_1BIT,
                             78, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(85, "CH5VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            79, UNIPHIER_PIN_DRV_4_8,
+                            79, UNIPHIER_PIN_DRV_1BIT,
                             79, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(86, "CH5PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            80, UNIPHIER_PIN_DRV_4_8,
+                            80, UNIPHIER_PIN_DRV_1BIT,
                             80, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(87, "CH5DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            81, UNIPHIER_PIN_DRV_4_8,
+                            81, UNIPHIER_PIN_DRV_1BIT,
                             81, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(88, "CH6CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            82, UNIPHIER_PIN_DRV_4_8,
+                            82, UNIPHIER_PIN_DRV_1BIT,
                             82, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(89, "CH6VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            83, UNIPHIER_PIN_DRV_4_8,
+                            83, UNIPHIER_PIN_DRV_1BIT,
                             83, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(90, "CH6PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            84, UNIPHIER_PIN_DRV_4_8,
+                            84, UNIPHIER_PIN_DRV_1BIT,
                             84, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(91, "CH6DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            85, UNIPHIER_PIN_DRV_4_8,
+                            85, UNIPHIER_PIN_DRV_1BIT,
                             85, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(92, "CKFEO", UNIPHIER_PIN_IECTRL_NONE,
-                            86, UNIPHIER_PIN_DRV_4_8,
+                            86, UNIPHIER_PIN_DRV_1BIT,
                             86, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(93, "XFERST", UNIPHIER_PIN_IECTRL_NONE,
-                            87, UNIPHIER_PIN_DRV_4_8,
+                            87, UNIPHIER_PIN_DRV_1BIT,
                             87, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(94, "P_FE_ON", UNIPHIER_PIN_IECTRL_NONE,
-                            88, UNIPHIER_PIN_DRV_4_8,
+                            88, UNIPHIER_PIN_DRV_1BIT,
                             88, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(95, "P_TU0_ON", UNIPHIER_PIN_IECTRL_NONE,
-                            89, UNIPHIER_PIN_DRV_4_8,
+                            89, UNIPHIER_PIN_DRV_1BIT,
                             89, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(96, "XFEIRQ0", UNIPHIER_PIN_IECTRL_NONE,
-                            90, UNIPHIER_PIN_DRV_4_8,
+                            90, UNIPHIER_PIN_DRV_1BIT,
                             90, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(97, "XFEIRQ1", UNIPHIER_PIN_IECTRL_NONE,
-                            91, UNIPHIER_PIN_DRV_4_8,
+                            91, UNIPHIER_PIN_DRV_1BIT,
                             91, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(98, "XFEIRQ2", UNIPHIER_PIN_IECTRL_NONE,
-                            92, UNIPHIER_PIN_DRV_4_8,
+                            92, UNIPHIER_PIN_DRV_1BIT,
                             92, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(99, "XFEIRQ3", UNIPHIER_PIN_IECTRL_NONE,
-                            93, UNIPHIER_PIN_DRV_4_8,
+                            93, UNIPHIER_PIN_DRV_1BIT,
                             93, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(100, "XFEIRQ4", UNIPHIER_PIN_IECTRL_NONE,
-                            94, UNIPHIER_PIN_DRV_4_8,
+                            94, UNIPHIER_PIN_DRV_1BIT,
                             94, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(101, "XFEIRQ5", UNIPHIER_PIN_IECTRL_NONE,
-                            95, UNIPHIER_PIN_DRV_4_8,
+                            95, UNIPHIER_PIN_DRV_1BIT,
                             95, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(102, "XFEIRQ6", UNIPHIER_PIN_IECTRL_NONE,
-                            96, UNIPHIER_PIN_DRV_4_8,
+                            96, UNIPHIER_PIN_DRV_1BIT,
                             96, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(103, "SMTCLK0", UNIPHIER_PIN_IECTRL_NONE,
-                            97, UNIPHIER_PIN_DRV_4_8,
+                            97, UNIPHIER_PIN_DRV_1BIT,
                             97, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(104, "SMTRST0", UNIPHIER_PIN_IECTRL_NONE,
-                            98, UNIPHIER_PIN_DRV_4_8,
+                            98, UNIPHIER_PIN_DRV_1BIT,
                             98, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(105, "SMTCMD0", UNIPHIER_PIN_IECTRL_NONE,
-                            99, UNIPHIER_PIN_DRV_4_8,
+                            99, UNIPHIER_PIN_DRV_1BIT,
                             99, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(106, "SMTD0", UNIPHIER_PIN_IECTRL_NONE,
-                            100, UNIPHIER_PIN_DRV_4_8,
+                            100, UNIPHIER_PIN_DRV_1BIT,
                             100, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(107, "SMTSEL0", UNIPHIER_PIN_IECTRL_NONE,
-                            101, UNIPHIER_PIN_DRV_4_8,
+                            101, UNIPHIER_PIN_DRV_1BIT,
                             101, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(108, "SMTDET0", UNIPHIER_PIN_IECTRL_NONE,
-                            102, UNIPHIER_PIN_DRV_4_8,
+                            102, UNIPHIER_PIN_DRV_1BIT,
                             102, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(109, "SMTCLK1", UNIPHIER_PIN_IECTRL_NONE,
-                            103, UNIPHIER_PIN_DRV_4_8,
+                            103, UNIPHIER_PIN_DRV_1BIT,
                             103, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(110, "SMTRST1", UNIPHIER_PIN_IECTRL_NONE,
-                            104, UNIPHIER_PIN_DRV_4_8,
+                            104, UNIPHIER_PIN_DRV_1BIT,
                             104, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(111, "SMTCMD1", UNIPHIER_PIN_IECTRL_NONE,
-                            105, UNIPHIER_PIN_DRV_4_8,
+                            105, UNIPHIER_PIN_DRV_1BIT,
                             105, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(112, "SMTD1", UNIPHIER_PIN_IECTRL_NONE,
-                            106, UNIPHIER_PIN_DRV_4_8,
+                            106, UNIPHIER_PIN_DRV_1BIT,
                             106, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(113, "SMTSEL1", UNIPHIER_PIN_IECTRL_NONE,
-                            107, UNIPHIER_PIN_DRV_4_8,
+                            107, UNIPHIER_PIN_DRV_1BIT,
                             107, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(114, "SMTDET1", UNIPHIER_PIN_IECTRL_NONE,
-                            108, UNIPHIER_PIN_DRV_4_8,
+                            108, UNIPHIER_PIN_DRV_1BIT,
                             108, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(115, "XINTM", UNIPHIER_PIN_IECTRL_NONE,
-                            109, UNIPHIER_PIN_DRV_4_8,
+                            109, UNIPHIER_PIN_DRV_1BIT,
                             109, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(116, "SCLKM", UNIPHIER_PIN_IECTRL_NONE,
-                            110, UNIPHIER_PIN_DRV_4_8,
+                            110, UNIPHIER_PIN_DRV_1BIT,
                             110, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(117, "SBMTP", UNIPHIER_PIN_IECTRL_NONE,
-                            111, UNIPHIER_PIN_DRV_4_8,
+                            111, UNIPHIER_PIN_DRV_1BIT,
                             111, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(118, "SBPTM", UNIPHIER_PIN_IECTRL_NONE,
-                            112, UNIPHIER_PIN_DRV_4_8,
+                            112, UNIPHIER_PIN_DRV_1BIT,
                             112, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(119, "XMPREQ", UNIPHIER_PIN_IECTRL_NONE,
-                            113, UNIPHIER_PIN_DRV_4_8,
+                            113, UNIPHIER_PIN_DRV_1BIT,
                             113, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(120, "XINTP", UNIPHIER_PIN_IECTRL_NONE,
-                            114, UNIPHIER_PIN_DRV_4_8,
+                            114, UNIPHIER_PIN_DRV_1BIT,
                             114, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(121, "LPST", UNIPHIER_PIN_IECTRL_NONE,
-                            115, UNIPHIER_PIN_DRV_4_8,
+                            115, UNIPHIER_PIN_DRV_1BIT,
                             115, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(122, "SDBOOT", UNIPHIER_PIN_IECTRL_NONE,
-                            116, UNIPHIER_PIN_DRV_4_8,
+                            116, UNIPHIER_PIN_DRV_1BIT,
                             116, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(123, "BFAIL", UNIPHIER_PIN_IECTRL_NONE,
-                            117, UNIPHIER_PIN_DRV_4_8,
+                            117, UNIPHIER_PIN_DRV_1BIT,
                             117, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(124, "XFWE", UNIPHIER_PIN_IECTRL_NONE,
-                            118, UNIPHIER_PIN_DRV_4_8,
+                            118, UNIPHIER_PIN_DRV_1BIT,
                             118, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(125, "RF_COM_RDY", UNIPHIER_PIN_IECTRL_NONE,
-                            119, UNIPHIER_PIN_DRV_4_8,
+                            119, UNIPHIER_PIN_DRV_1BIT,
                             119, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(126, "XDIAG0", UNIPHIER_PIN_IECTRL_NONE,
-                            120, UNIPHIER_PIN_DRV_4_8,
+                            120, UNIPHIER_PIN_DRV_1BIT,
                             120, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(127, "RXD0", UNIPHIER_PIN_IECTRL_NONE,
-                            121, UNIPHIER_PIN_DRV_4_8,
+                            121, UNIPHIER_PIN_DRV_1BIT,
                             121, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(128, "TXD0", UNIPHIER_PIN_IECTRL_NONE,
-                            122, UNIPHIER_PIN_DRV_4_8,
+                            122, UNIPHIER_PIN_DRV_1BIT,
                             122, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(129, "RXD1", UNIPHIER_PIN_IECTRL_NONE,
-                            123, UNIPHIER_PIN_DRV_4_8,
+                            123, UNIPHIER_PIN_DRV_1BIT,
                             123, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(130, "TXD1", UNIPHIER_PIN_IECTRL_NONE,
-                            124, UNIPHIER_PIN_DRV_4_8,
+                            124, UNIPHIER_PIN_DRV_1BIT,
                             124, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(131, "RXD2", UNIPHIER_PIN_IECTRL_NONE,
-                            125, UNIPHIER_PIN_DRV_4_8,
+                            125, UNIPHIER_PIN_DRV_1BIT,
                             125, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(132, "TXD2", UNIPHIER_PIN_IECTRL_NONE,
-                            126, UNIPHIER_PIN_DRV_4_8,
+                            126, UNIPHIER_PIN_DRV_1BIT,
                             126, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(133, "SS0CS", UNIPHIER_PIN_IECTRL_NONE,
-                            127, UNIPHIER_PIN_DRV_4_8,
+                            127, UNIPHIER_PIN_DRV_1BIT,
                             127, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(134, "SS0CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            128, UNIPHIER_PIN_DRV_4_8,
+                            128, UNIPHIER_PIN_DRV_1BIT,
                             128, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(135, "SS0DO", UNIPHIER_PIN_IECTRL_NONE,
-                            129, UNIPHIER_PIN_DRV_4_8,
+                            129, UNIPHIER_PIN_DRV_1BIT,
                             129, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(136, "SS0DI", UNIPHIER_PIN_IECTRL_NONE,
-                            130, UNIPHIER_PIN_DRV_4_8,
+                            130, UNIPHIER_PIN_DRV_1BIT,
                             130, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(137, "MS0CS0", UNIPHIER_PIN_IECTRL_NONE,
-                            131, UNIPHIER_PIN_DRV_4_8,
+                            131, UNIPHIER_PIN_DRV_1BIT,
                             131, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(138, "MS0CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            132, UNIPHIER_PIN_DRV_4_8,
+                            132, UNIPHIER_PIN_DRV_1BIT,
                             132, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(139, "MS0DI", UNIPHIER_PIN_IECTRL_NONE,
-                            133, UNIPHIER_PIN_DRV_4_8,
+                            133, UNIPHIER_PIN_DRV_1BIT,
                             133, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(140, "MS0DO", UNIPHIER_PIN_IECTRL_NONE,
-                            134, UNIPHIER_PIN_DRV_4_8,
+                            134, UNIPHIER_PIN_DRV_1BIT,
                             134, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(141, "XMDMRST", UNIPHIER_PIN_IECTRL_NONE,
-                            135, UNIPHIER_PIN_DRV_4_8,
+                            135, UNIPHIER_PIN_DRV_1BIT,
                             135, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(142, "SCL0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(143, "SDA0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(144, "SCL1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(145, "SDA1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(146, "SCL2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(147, "SDA2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(148, "SCL3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(149, "SDA3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(150, "SD0DAT0", UNIPHIER_PIN_IECTRL_NONE,
-                            12, UNIPHIER_PIN_DRV_8_12_16_20,
+                            12, UNIPHIER_PIN_DRV_2BIT,
                             136, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(151, "SD0DAT1", UNIPHIER_PIN_IECTRL_NONE,
-                            13, UNIPHIER_PIN_DRV_8_12_16_20,
+                            13, UNIPHIER_PIN_DRV_2BIT,
                             137, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(152, "SD0DAT2", UNIPHIER_PIN_IECTRL_NONE,
-                            14, UNIPHIER_PIN_DRV_8_12_16_20,
+                            14, UNIPHIER_PIN_DRV_2BIT,
                             138, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(153, "SD0DAT3", UNIPHIER_PIN_IECTRL_NONE,
-                            15, UNIPHIER_PIN_DRV_8_12_16_20,
+                            15, UNIPHIER_PIN_DRV_2BIT,
                             139, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(154, "SD0CMD", UNIPHIER_PIN_IECTRL_NONE,
-                            11, UNIPHIER_PIN_DRV_8_12_16_20,
+                            11, UNIPHIER_PIN_DRV_2BIT,
                             141, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(155, "SD0CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            10, UNIPHIER_PIN_DRV_8_12_16_20,
+                            10, UNIPHIER_PIN_DRV_2BIT,
                             140, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(156, "SD0CD", UNIPHIER_PIN_IECTRL_NONE,
-                            142, UNIPHIER_PIN_DRV_4_8,
+                            142, UNIPHIER_PIN_DRV_1BIT,
                             142, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(157, "SD0WP", UNIPHIER_PIN_IECTRL_NONE,
-                            143, UNIPHIER_PIN_DRV_4_8,
+                            143, UNIPHIER_PIN_DRV_1BIT,
                             143, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(158, "SD0VTCG", UNIPHIER_PIN_IECTRL_NONE,
-                            144, UNIPHIER_PIN_DRV_4_8,
+                            144, UNIPHIER_PIN_DRV_1BIT,
                             144, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(159, "CK25O", UNIPHIER_PIN_IECTRL_NONE,
-                            145, UNIPHIER_PIN_DRV_4_8,
+                            145, UNIPHIER_PIN_DRV_1BIT,
                             145, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(160, "RGMII_TXCLK", 6,
-                            146, UNIPHIER_PIN_DRV_4_8,
+                            146, UNIPHIER_PIN_DRV_1BIT,
                             146, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(161, "RGMII_TXD0", 6,
-                            147, UNIPHIER_PIN_DRV_4_8,
+                            147, UNIPHIER_PIN_DRV_1BIT,
                             147, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(162, "RGMII_TXD1", 6,
-                            148, UNIPHIER_PIN_DRV_4_8,
+                            148, UNIPHIER_PIN_DRV_1BIT,
                             148, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(163, "RGMII_TXD2", 6,
-                            149, UNIPHIER_PIN_DRV_4_8,
+                            149, UNIPHIER_PIN_DRV_1BIT,
                             149, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(164, "RGMII_TXD3", 6,
-                            150, UNIPHIER_PIN_DRV_4_8,
+                            150, UNIPHIER_PIN_DRV_1BIT,
                             150, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(165, "RGMII_TXCTL", 6,
-                            151, UNIPHIER_PIN_DRV_4_8,
+                            151, UNIPHIER_PIN_DRV_1BIT,
                             151, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(166, "MII_TXER", UNIPHIER_PIN_IECTRL_NONE,
-                            152, UNIPHIER_PIN_DRV_4_8,
+                            152, UNIPHIER_PIN_DRV_1BIT,
                             152, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(167, "RGMII_RXCLK", 6,
-                            153, UNIPHIER_PIN_DRV_4_8,
+                            153, UNIPHIER_PIN_DRV_1BIT,
                             153, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(168, "RGMII_RXD0", 6,
-                            154, UNIPHIER_PIN_DRV_4_8,
+                            154, UNIPHIER_PIN_DRV_1BIT,
                             154, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(169, "RGMII_RXD1", 6,
-                            155, UNIPHIER_PIN_DRV_4_8,
+                            155, UNIPHIER_PIN_DRV_1BIT,
                             155, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(170, "RGMII_RXD2", 6,
-                            156, UNIPHIER_PIN_DRV_4_8,
+                            156, UNIPHIER_PIN_DRV_1BIT,
                             156, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(171, "RGMII_RXD3", 6,
-                            157, UNIPHIER_PIN_DRV_4_8,
+                            157, UNIPHIER_PIN_DRV_1BIT,
                             157, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(172, "RGMII_RXCTL", 6,
-                            158, UNIPHIER_PIN_DRV_4_8,
+                            158, UNIPHIER_PIN_DRV_1BIT,
                             158, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(173, "MII_RXER", 6,
-                            159, UNIPHIER_PIN_DRV_4_8,
+                            159, UNIPHIER_PIN_DRV_1BIT,
                             159, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(174, "MII_CRS", 6,
-                            160, UNIPHIER_PIN_DRV_4_8,
+                            160, UNIPHIER_PIN_DRV_1BIT,
                             160, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(175, "MII_COL", 6,
-                            161, UNIPHIER_PIN_DRV_4_8,
+                            161, UNIPHIER_PIN_DRV_1BIT,
                             161, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(176, "MDC", 6,
-                            162, UNIPHIER_PIN_DRV_4_8,
+                            162, UNIPHIER_PIN_DRV_1BIT,
                             162, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(177, "MDIO", 6,
-                            163, UNIPHIER_PIN_DRV_4_8,
+                            163, UNIPHIER_PIN_DRV_1BIT,
                             163, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(178, "MDIO_INTL", 6,
-                            164, UNIPHIER_PIN_DRV_4_8,
+                            164, UNIPHIER_PIN_DRV_1BIT,
                             164, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(179, "XETH_RST", 6,
-                            165, UNIPHIER_PIN_DRV_4_8,
+                            165, UNIPHIER_PIN_DRV_1BIT,
                             165, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(180, "USB0VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            166, UNIPHIER_PIN_DRV_4_8,
+                            166, UNIPHIER_PIN_DRV_1BIT,
                             166, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(181, "USB0OD", UNIPHIER_PIN_IECTRL_NONE,
-                            167, UNIPHIER_PIN_DRV_4_8,
+                            167, UNIPHIER_PIN_DRV_1BIT,
                             167, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(182, "USB1VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            168, UNIPHIER_PIN_DRV_4_8,
+                            168, UNIPHIER_PIN_DRV_1BIT,
                             168, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(183, "USB1OD", UNIPHIER_PIN_IECTRL_NONE,
-                            169, UNIPHIER_PIN_DRV_4_8,
+                            169, UNIPHIER_PIN_DRV_1BIT,
                             169, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(184, "USB2VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            170, UNIPHIER_PIN_DRV_4_8,
+                            170, UNIPHIER_PIN_DRV_1BIT,
                             170, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(185, "USB2OD", UNIPHIER_PIN_IECTRL_NONE,
-                            171, UNIPHIER_PIN_DRV_4_8,
+                            171, UNIPHIER_PIN_DRV_1BIT,
                             171, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(186, "USB2ID", UNIPHIER_PIN_IECTRL_NONE,
-                            172, UNIPHIER_PIN_DRV_4_8,
+                            172, UNIPHIER_PIN_DRV_1BIT,
                             172, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(187, "USB3VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            173, UNIPHIER_PIN_DRV_4_8,
+                            173, UNIPHIER_PIN_DRV_1BIT,
                             173, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(188, "USB3OD", UNIPHIER_PIN_IECTRL_NONE,
-                            174, UNIPHIER_PIN_DRV_4_8,
+                            174, UNIPHIER_PIN_DRV_1BIT,
                             174, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(189, "LINKCLK", UNIPHIER_PIN_IECTRL_NONE,
-                            175, UNIPHIER_PIN_DRV_4_8,
+                            175, UNIPHIER_PIN_DRV_1BIT,
                             175, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(190, "LINKREQ", UNIPHIER_PIN_IECTRL_NONE,
-                            176, UNIPHIER_PIN_DRV_4_8,
+                            176, UNIPHIER_PIN_DRV_1BIT,
                             176, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(191, "LINKCTL0", UNIPHIER_PIN_IECTRL_NONE,
-                            177, UNIPHIER_PIN_DRV_4_8,
+                            177, UNIPHIER_PIN_DRV_1BIT,
                             177, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(192, "LINKCTL1", UNIPHIER_PIN_IECTRL_NONE,
-                            178, UNIPHIER_PIN_DRV_4_8,
+                            178, UNIPHIER_PIN_DRV_1BIT,
                             178, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(193, "LINKDT0", UNIPHIER_PIN_IECTRL_NONE,
-                            179, UNIPHIER_PIN_DRV_4_8,
+                            179, UNIPHIER_PIN_DRV_1BIT,
                             179, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(194, "LINKDT1", UNIPHIER_PIN_IECTRL_NONE,
-                            180, UNIPHIER_PIN_DRV_4_8,
+                            180, UNIPHIER_PIN_DRV_1BIT,
                             180, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(195, "LINKDT2", UNIPHIER_PIN_IECTRL_NONE,
-                            181, UNIPHIER_PIN_DRV_4_8,
+                            181, UNIPHIER_PIN_DRV_1BIT,
                             181, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(196, "LINKDT3", UNIPHIER_PIN_IECTRL_NONE,
-                            182, UNIPHIER_PIN_DRV_4_8,
+                            182, UNIPHIER_PIN_DRV_1BIT,
                             182, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(197, "LINKDT4", UNIPHIER_PIN_IECTRL_NONE,
-                            183, UNIPHIER_PIN_DRV_4_8,
+                            183, UNIPHIER_PIN_DRV_1BIT,
                             183, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(198, "LINKDT5", UNIPHIER_PIN_IECTRL_NONE,
-                            184, UNIPHIER_PIN_DRV_4_8,
+                            184, UNIPHIER_PIN_DRV_1BIT,
                             184, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(199, "LINKDT6", UNIPHIER_PIN_IECTRL_NONE,
-                            185, UNIPHIER_PIN_DRV_4_8,
+                            185, UNIPHIER_PIN_DRV_1BIT,
                             185, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(200, "LINKDT7", UNIPHIER_PIN_IECTRL_NONE,
-                            186, UNIPHIER_PIN_DRV_4_8,
+                            186, UNIPHIER_PIN_DRV_1BIT,
                             186, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(201, "CKDVO", UNIPHIER_PIN_IECTRL_NONE,
-                            187, UNIPHIER_PIN_DRV_4_8,
+                            187, UNIPHIER_PIN_DRV_1BIT,
                             187, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(202, "PHY_PD", UNIPHIER_PIN_IECTRL_NONE,
-                            188, UNIPHIER_PIN_DRV_4_8,
+                            188, UNIPHIER_PIN_DRV_1BIT,
                             188, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(203, "X1394_RST", UNIPHIER_PIN_IECTRL_NONE,
-                            189, UNIPHIER_PIN_DRV_4_8,
+                            189, UNIPHIER_PIN_DRV_1BIT,
                             189, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(204, "VOUT_MUTE_L", UNIPHIER_PIN_IECTRL_NONE,
-                            190, UNIPHIER_PIN_DRV_4_8,
+                            190, UNIPHIER_PIN_DRV_1BIT,
                             190, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(205, "CLK54O", UNIPHIER_PIN_IECTRL_NONE,
-                            191, UNIPHIER_PIN_DRV_4_8,
+                            191, UNIPHIER_PIN_DRV_1BIT,
                             191, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(206, "CLK54I", UNIPHIER_PIN_IECTRL_NONE,
-                            192, UNIPHIER_PIN_DRV_NONE,
+                            -1, UNIPHIER_PIN_DRV_NONE,
                             192, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(207, "YIN0", UNIPHIER_PIN_IECTRL_NONE,
-                            193, UNIPHIER_PIN_DRV_4_8,
+                            193, UNIPHIER_PIN_DRV_1BIT,
                             193, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(208, "YIN1", UNIPHIER_PIN_IECTRL_NONE,
-                            194, UNIPHIER_PIN_DRV_4_8,
+                            194, UNIPHIER_PIN_DRV_1BIT,
                             194, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(209, "YIN2", UNIPHIER_PIN_IECTRL_NONE,
-                            195, UNIPHIER_PIN_DRV_4_8,
+                            195, UNIPHIER_PIN_DRV_1BIT,
                             195, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(210, "YIN3", UNIPHIER_PIN_IECTRL_NONE,
-                            196, UNIPHIER_PIN_DRV_4_8,
+                            196, UNIPHIER_PIN_DRV_1BIT,
                             196, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(211, "YIN4", UNIPHIER_PIN_IECTRL_NONE,
-                            197, UNIPHIER_PIN_DRV_4_8,
+                            197, UNIPHIER_PIN_DRV_1BIT,
                             197, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(212, "YIN5", UNIPHIER_PIN_IECTRL_NONE,
-                            198, UNIPHIER_PIN_DRV_4_8,
+                            198, UNIPHIER_PIN_DRV_1BIT,
                             198, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(213, "CIN0", UNIPHIER_PIN_IECTRL_NONE,
-                            199, UNIPHIER_PIN_DRV_4_8,
+                            199, UNIPHIER_PIN_DRV_1BIT,
                             199, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(214, "CIN1", UNIPHIER_PIN_IECTRL_NONE,
-                            200, UNIPHIER_PIN_DRV_4_8,
+                            200, UNIPHIER_PIN_DRV_1BIT,
                             200, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(215, "CIN2", UNIPHIER_PIN_IECTRL_NONE,
-                            201, UNIPHIER_PIN_DRV_4_8,
+                            201, UNIPHIER_PIN_DRV_1BIT,
                             201, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(216, "CIN3", UNIPHIER_PIN_IECTRL_NONE,
-                            202, UNIPHIER_PIN_DRV_4_8,
+                            202, UNIPHIER_PIN_DRV_1BIT,
                             202, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(217, "CIN4", UNIPHIER_PIN_IECTRL_NONE,
-                            203, UNIPHIER_PIN_DRV_4_8,
+                            203, UNIPHIER_PIN_DRV_1BIT,
                             203, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(218, "CIN5", UNIPHIER_PIN_IECTRL_NONE,
-                            204, UNIPHIER_PIN_DRV_4_8,
+                            204, UNIPHIER_PIN_DRV_1BIT,
                             204, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(219, "GCP", UNIPHIER_PIN_IECTRL_NONE,
-                            205, UNIPHIER_PIN_DRV_4_8,
+                            205, UNIPHIER_PIN_DRV_1BIT,
                             205, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(220, "ADFLG", UNIPHIER_PIN_IECTRL_NONE,
-                            206, UNIPHIER_PIN_DRV_4_8,
+                            206, UNIPHIER_PIN_DRV_1BIT,
                             206, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(221, "CK27AIOF", UNIPHIER_PIN_IECTRL_NONE,
-                            207, UNIPHIER_PIN_DRV_4_8,
+                            207, UNIPHIER_PIN_DRV_1BIT,
                             207, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(222, "DACOUT", UNIPHIER_PIN_IECTRL_NONE,
-                            208, UNIPHIER_PIN_DRV_4_8,
+                            208, UNIPHIER_PIN_DRV_1BIT,
                             208, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(223, "DAFLG", UNIPHIER_PIN_IECTRL_NONE,
-                            209, UNIPHIER_PIN_DRV_4_8,
+                            209, UNIPHIER_PIN_DRV_1BIT,
                             209, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(224, "VBIH", UNIPHIER_PIN_IECTRL_NONE,
-                            210, UNIPHIER_PIN_DRV_4_8,
+                            210, UNIPHIER_PIN_DRV_1BIT,
                             210, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(225, "VBIL", UNIPHIER_PIN_IECTRL_NONE,
-                            211, UNIPHIER_PIN_DRV_4_8,
+                            211, UNIPHIER_PIN_DRV_1BIT,
                             211, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(226, "XSUB_RST", UNIPHIER_PIN_IECTRL_NONE,
-                            212, UNIPHIER_PIN_DRV_4_8,
+                            212, UNIPHIER_PIN_DRV_1BIT,
                             212, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(227, "XADC_PD", UNIPHIER_PIN_IECTRL_NONE,
-                            213, UNIPHIER_PIN_DRV_4_8,
+                            213, UNIPHIER_PIN_DRV_1BIT,
                             213, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(228, "AI1ADCCK", UNIPHIER_PIN_IECTRL_NONE,
-                            214, UNIPHIER_PIN_DRV_4_8,
+                            214, UNIPHIER_PIN_DRV_1BIT,
                             214, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(229, "AI1BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            215, UNIPHIER_PIN_DRV_4_8,
+                            215, UNIPHIER_PIN_DRV_1BIT,
                             215, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(230, "AI1LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            216, UNIPHIER_PIN_DRV_4_8,
+                            216, UNIPHIER_PIN_DRV_1BIT,
                             216, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(231, "AI1DMIX", UNIPHIER_PIN_IECTRL_NONE,
-                            217, UNIPHIER_PIN_DRV_4_8,
+                            217, UNIPHIER_PIN_DRV_1BIT,
                             217, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(232, "CK27HD", UNIPHIER_PIN_IECTRL_NONE,
-                            218, UNIPHIER_PIN_DRV_4_8,
+                            218, UNIPHIER_PIN_DRV_1BIT,
                             218, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(233, "XHD_RST", UNIPHIER_PIN_IECTRL_NONE,
-                            219, UNIPHIER_PIN_DRV_4_8,
+                            219, UNIPHIER_PIN_DRV_1BIT,
                             219, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(234, "INTHD", UNIPHIER_PIN_IECTRL_NONE,
-                            220, UNIPHIER_PIN_DRV_4_8,
+                            220, UNIPHIER_PIN_DRV_1BIT,
                             220, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(235, "VO1HDCK", UNIPHIER_PIN_IECTRL_NONE,
-                            221, UNIPHIER_PIN_DRV_4_8,
+                            221, UNIPHIER_PIN_DRV_1BIT,
                             221, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(236, "VO1HSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            222, UNIPHIER_PIN_DRV_4_8,
+                            222, UNIPHIER_PIN_DRV_1BIT,
                             222, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(237, "VO1VSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            223, UNIPHIER_PIN_DRV_4_8,
+                            223, UNIPHIER_PIN_DRV_1BIT,
                             223, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(238, "VO1DE", UNIPHIER_PIN_IECTRL_NONE,
-                            224, UNIPHIER_PIN_DRV_4_8,
+                            224, UNIPHIER_PIN_DRV_1BIT,
                             224, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(239, "VO1Y0", UNIPHIER_PIN_IECTRL_NONE,
-                            225, UNIPHIER_PIN_DRV_4_8,
+                            225, UNIPHIER_PIN_DRV_1BIT,
                             225, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(240, "VO1Y1", UNIPHIER_PIN_IECTRL_NONE,
-                            226, UNIPHIER_PIN_DRV_4_8,
+                            226, UNIPHIER_PIN_DRV_1BIT,
                             226, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(241, "VO1Y2", UNIPHIER_PIN_IECTRL_NONE,
-                            227, UNIPHIER_PIN_DRV_4_8,
+                            227, UNIPHIER_PIN_DRV_1BIT,
                             227, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(242, "VO1Y3", UNIPHIER_PIN_IECTRL_NONE,
-                            228, UNIPHIER_PIN_DRV_4_8,
+                            228, UNIPHIER_PIN_DRV_1BIT,
                             228, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(243, "VO1Y4", UNIPHIER_PIN_IECTRL_NONE,
-                            229, UNIPHIER_PIN_DRV_4_8,
+                            229, UNIPHIER_PIN_DRV_1BIT,
                             229, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(244, "VO1Y5", UNIPHIER_PIN_IECTRL_NONE,
-                            230, UNIPHIER_PIN_DRV_4_8,
+                            230, UNIPHIER_PIN_DRV_1BIT,
                             230, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(245, "VO1Y6", UNIPHIER_PIN_IECTRL_NONE,
-                            231, UNIPHIER_PIN_DRV_4_8,
+                            231, UNIPHIER_PIN_DRV_1BIT,
                             231, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(246, "VO1Y7", UNIPHIER_PIN_IECTRL_NONE,
-                            232, UNIPHIER_PIN_DRV_4_8,
+                            232, UNIPHIER_PIN_DRV_1BIT,
                             232, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(247, "VO1Y8", UNIPHIER_PIN_IECTRL_NONE,
-                            233, UNIPHIER_PIN_DRV_4_8,
+                            233, UNIPHIER_PIN_DRV_1BIT,
                             233, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(248, "VO1Y9", UNIPHIER_PIN_IECTRL_NONE,
-                            234, UNIPHIER_PIN_DRV_4_8,
+                            234, UNIPHIER_PIN_DRV_1BIT,
                             234, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(249, "VO1Y10", UNIPHIER_PIN_IECTRL_NONE,
-                            235, UNIPHIER_PIN_DRV_4_8,
+                            235, UNIPHIER_PIN_DRV_1BIT,
                             235, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(250, "VO1Y11", UNIPHIER_PIN_IECTRL_NONE,
-                            236, UNIPHIER_PIN_DRV_4_8,
+                            236, UNIPHIER_PIN_DRV_1BIT,
                             236, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(251, "VO1CB0", UNIPHIER_PIN_IECTRL_NONE,
-                            237, UNIPHIER_PIN_DRV_4_8,
+                            237, UNIPHIER_PIN_DRV_1BIT,
                             237, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(252, "VO1CB1", UNIPHIER_PIN_IECTRL_NONE,
-                            238, UNIPHIER_PIN_DRV_4_8,
+                            238, UNIPHIER_PIN_DRV_1BIT,
                             238, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(253, "VO1CB2", UNIPHIER_PIN_IECTRL_NONE,
-                            239, UNIPHIER_PIN_DRV_4_8,
+                            239, UNIPHIER_PIN_DRV_1BIT,
                             239, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(254, "VO1CB3", UNIPHIER_PIN_IECTRL_NONE,
-                            240, UNIPHIER_PIN_DRV_4_8,
+                            240, UNIPHIER_PIN_DRV_1BIT,
                             240, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(255, "VO1CB4", UNIPHIER_PIN_IECTRL_NONE,
-                            241, UNIPHIER_PIN_DRV_4_8,
+                            241, UNIPHIER_PIN_DRV_1BIT,
                             241, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(256, "VO1CB5", UNIPHIER_PIN_IECTRL_NONE,
-                            242, UNIPHIER_PIN_DRV_4_8,
+                            242, UNIPHIER_PIN_DRV_1BIT,
                             242, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(257, "VO1CB6", UNIPHIER_PIN_IECTRL_NONE,
-                            243, UNIPHIER_PIN_DRV_4_8,
+                            243, UNIPHIER_PIN_DRV_1BIT,
                             243, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(258, "VO1CB7", UNIPHIER_PIN_IECTRL_NONE,
-                            244, UNIPHIER_PIN_DRV_4_8,
+                            244, UNIPHIER_PIN_DRV_1BIT,
                             244, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(259, "VO1CB8", UNIPHIER_PIN_IECTRL_NONE,
-                            245, UNIPHIER_PIN_DRV_4_8,
+                            245, UNIPHIER_PIN_DRV_1BIT,
                             245, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(260, "VO1CB9", UNIPHIER_PIN_IECTRL_NONE,
-                            246, UNIPHIER_PIN_DRV_4_8,
+                            246, UNIPHIER_PIN_DRV_1BIT,
                             246, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(261, "VO1CB10", UNIPHIER_PIN_IECTRL_NONE,
-                            247, UNIPHIER_PIN_DRV_4_8,
+                            247, UNIPHIER_PIN_DRV_1BIT,
                             247, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(262, "VO1CB11", UNIPHIER_PIN_IECTRL_NONE,
-                            248, UNIPHIER_PIN_DRV_4_8,
+                            248, UNIPHIER_PIN_DRV_1BIT,
                             248, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(263, "VO1CR0", UNIPHIER_PIN_IECTRL_NONE,
-                            249, UNIPHIER_PIN_DRV_4_8,
+                            249, UNIPHIER_PIN_DRV_1BIT,
                             249, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(264, "VO1CR1", UNIPHIER_PIN_IECTRL_NONE,
-                            250, UNIPHIER_PIN_DRV_4_8,
+                            250, UNIPHIER_PIN_DRV_1BIT,
                             250, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(265, "VO1CR2", UNIPHIER_PIN_IECTRL_NONE,
-                            251, UNIPHIER_PIN_DRV_4_8,
+                            251, UNIPHIER_PIN_DRV_1BIT,
                             251, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(266, "VO1CR3", UNIPHIER_PIN_IECTRL_NONE,
-                            252, UNIPHIER_PIN_DRV_4_8,
+                            252, UNIPHIER_PIN_DRV_1BIT,
                             252, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(267, "VO1CR4", UNIPHIER_PIN_IECTRL_NONE,
-                            253, UNIPHIER_PIN_DRV_4_8,
+                            253, UNIPHIER_PIN_DRV_1BIT,
                             253, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(268, "VO1CR5", UNIPHIER_PIN_IECTRL_NONE,
-                            254, UNIPHIER_PIN_DRV_4_8,
+                            254, UNIPHIER_PIN_DRV_1BIT,
                             254, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(269, "VO1CR6", UNIPHIER_PIN_IECTRL_NONE,
-                            255, UNIPHIER_PIN_DRV_4_8,
+                            255, UNIPHIER_PIN_DRV_1BIT,
                             255, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(270, "VO1CR7", UNIPHIER_PIN_IECTRL_NONE,
-                            256, UNIPHIER_PIN_DRV_4_8,
+                            256, UNIPHIER_PIN_DRV_1BIT,
                             256, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(271, "VO1CR8", UNIPHIER_PIN_IECTRL_NONE,
-                            257, UNIPHIER_PIN_DRV_4_8,
+                            257, UNIPHIER_PIN_DRV_1BIT,
                             257, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(272, "VO1CR9", UNIPHIER_PIN_IECTRL_NONE,
-                            258, UNIPHIER_PIN_DRV_4_8,
+                            258, UNIPHIER_PIN_DRV_1BIT,
                             258, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(273, "VO1CR10", UNIPHIER_PIN_IECTRL_NONE,
-                            259, UNIPHIER_PIN_DRV_4_8,
+                            259, UNIPHIER_PIN_DRV_1BIT,
                             259, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(274, "VO1CR11", UNIPHIER_PIN_IECTRL_NONE,
-                            260, UNIPHIER_PIN_DRV_4_8,
+                            260, UNIPHIER_PIN_DRV_1BIT,
                             260, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(275, "VO1EX0", UNIPHIER_PIN_IECTRL_NONE,
-                            261, UNIPHIER_PIN_DRV_4_8,
+                            261, UNIPHIER_PIN_DRV_1BIT,
                             261, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(276, "VO1EX1", UNIPHIER_PIN_IECTRL_NONE,
-                            262, UNIPHIER_PIN_DRV_4_8,
+                            262, UNIPHIER_PIN_DRV_1BIT,
                             262, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(277, "VO1EX2", UNIPHIER_PIN_IECTRL_NONE,
-                            263, UNIPHIER_PIN_DRV_4_8,
+                            263, UNIPHIER_PIN_DRV_1BIT,
                             263, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(278, "VO1EX3", UNIPHIER_PIN_IECTRL_NONE,
-                            264, UNIPHIER_PIN_DRV_4_8,
+                            264, UNIPHIER_PIN_DRV_1BIT,
                             264, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(279, "VEXCKA", UNIPHIER_PIN_IECTRL_NONE,
-                            265, UNIPHIER_PIN_DRV_4_8,
+                            265, UNIPHIER_PIN_DRV_1BIT,
                             265, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(280, "VSEL0", UNIPHIER_PIN_IECTRL_NONE,
-                            266, UNIPHIER_PIN_DRV_4_8,
+                            266, UNIPHIER_PIN_DRV_1BIT,
                             266, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(281, "VSEL1", UNIPHIER_PIN_IECTRL_NONE,
-                            267, UNIPHIER_PIN_DRV_4_8,
+                            267, UNIPHIER_PIN_DRV_1BIT,
                             267, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(282, "AO1DACCK", UNIPHIER_PIN_IECTRL_NONE,
-                            268, UNIPHIER_PIN_DRV_4_8,
+                            268, UNIPHIER_PIN_DRV_1BIT,
                             268, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(283, "AO1BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            269, UNIPHIER_PIN_DRV_4_8,
+                            269, UNIPHIER_PIN_DRV_1BIT,
                             269, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(284, "AO1LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            270, UNIPHIER_PIN_DRV_4_8,
+                            270, UNIPHIER_PIN_DRV_1BIT,
                             270, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(285, "AO1D0", UNIPHIER_PIN_IECTRL_NONE,
-                            271, UNIPHIER_PIN_DRV_4_8,
+                            271, UNIPHIER_PIN_DRV_1BIT,
                             271, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(286, "AO1D1", UNIPHIER_PIN_IECTRL_NONE,
-                            272, UNIPHIER_PIN_DRV_4_8,
+                            272, UNIPHIER_PIN_DRV_1BIT,
                             272, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(287, "AO1D2", UNIPHIER_PIN_IECTRL_NONE,
-                            273, UNIPHIER_PIN_DRV_4_8,
+                            273, UNIPHIER_PIN_DRV_1BIT,
                             273, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(288, "AO1D3", UNIPHIER_PIN_IECTRL_NONE,
-                            274, UNIPHIER_PIN_DRV_4_8,
+                            274, UNIPHIER_PIN_DRV_1BIT,
                             274, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(289, "AO1IEC", UNIPHIER_PIN_IECTRL_NONE,
-                            275, UNIPHIER_PIN_DRV_4_8,
+                            275, UNIPHIER_PIN_DRV_1BIT,
                             275, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(290, "XDAC_PD", UNIPHIER_PIN_IECTRL_NONE,
-                            276, UNIPHIER_PIN_DRV_4_8,
+                            276, UNIPHIER_PIN_DRV_1BIT,
                             276, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(291, "EX_A_MUTE", UNIPHIER_PIN_IECTRL_NONE,
-                            277, UNIPHIER_PIN_DRV_4_8,
+                            277, UNIPHIER_PIN_DRV_1BIT,
                             277, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(292, "AO2DACCK", UNIPHIER_PIN_IECTRL_NONE,
-                            278, UNIPHIER_PIN_DRV_4_8,
+                            278, UNIPHIER_PIN_DRV_1BIT,
                             278, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(293, "AO2BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            279, UNIPHIER_PIN_DRV_4_8,
+                            279, UNIPHIER_PIN_DRV_1BIT,
                             279, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(294, "AO2LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            280, UNIPHIER_PIN_DRV_4_8,
+                            280, UNIPHIER_PIN_DRV_1BIT,
                             280, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(295, "AO2DMIX", UNIPHIER_PIN_IECTRL_NONE,
-                            281, UNIPHIER_PIN_DRV_4_8,
+                            281, UNIPHIER_PIN_DRV_1BIT,
                             281, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(296, "AO2IEC", UNIPHIER_PIN_IECTRL_NONE,
-                            282, UNIPHIER_PIN_DRV_4_8,
+                            282, UNIPHIER_PIN_DRV_1BIT,
                             282, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(297, "HTHPD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_5,
+                            -1, UNIPHIER_PIN_DRV_FIXED5,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(298, "HTSCL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_5,
+                            -1, UNIPHIER_PIN_DRV_FIXED5,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(299, "HTSDA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_5,
+                            -1, UNIPHIER_PIN_DRV_FIXED5,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(300, "PORT00", UNIPHIER_PIN_IECTRL_NONE,
-                            284, UNIPHIER_PIN_DRV_4_8,
+                            284, UNIPHIER_PIN_DRV_1BIT,
                             284, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(301, "PORT01", UNIPHIER_PIN_IECTRL_NONE,
-                            285, UNIPHIER_PIN_DRV_4_8,
+                            285, UNIPHIER_PIN_DRV_1BIT,
                             285, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(302, "PORT02", UNIPHIER_PIN_IECTRL_NONE,
-                            286, UNIPHIER_PIN_DRV_4_8,
+                            286, UNIPHIER_PIN_DRV_1BIT,
                             286, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(303, "PORT03", UNIPHIER_PIN_IECTRL_NONE,
-                            287, UNIPHIER_PIN_DRV_4_8,
+                            287, UNIPHIER_PIN_DRV_1BIT,
                             287, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(304, "PORT04", UNIPHIER_PIN_IECTRL_NONE,
-                            288, UNIPHIER_PIN_DRV_4_8,
+                            288, UNIPHIER_PIN_DRV_1BIT,
                             288, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(305, "PORT05", UNIPHIER_PIN_IECTRL_NONE,
-                            289, UNIPHIER_PIN_DRV_4_8,
+                            289, UNIPHIER_PIN_DRV_1BIT,
                             289, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(306, "PORT06", UNIPHIER_PIN_IECTRL_NONE,
-                            290, UNIPHIER_PIN_DRV_4_8,
+                            290, UNIPHIER_PIN_DRV_1BIT,
                             290, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(307, "PORT07", UNIPHIER_PIN_IECTRL_NONE,
-                            291, UNIPHIER_PIN_DRV_4_8,
+                            291, UNIPHIER_PIN_DRV_1BIT,
                             291, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(308, "PORT10", UNIPHIER_PIN_IECTRL_NONE,
-                            292, UNIPHIER_PIN_DRV_4_8,
+                            292, UNIPHIER_PIN_DRV_1BIT,
                             292, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(309, "PORT11", UNIPHIER_PIN_IECTRL_NONE,
-                            293, UNIPHIER_PIN_DRV_4_8,
+                            293, UNIPHIER_PIN_DRV_1BIT,
                             293, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(310, "PORT12", UNIPHIER_PIN_IECTRL_NONE,
-                            294, UNIPHIER_PIN_DRV_4_8,
+                            294, UNIPHIER_PIN_DRV_1BIT,
                             294, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(311, "PORT13", UNIPHIER_PIN_IECTRL_NONE,
-                            295, UNIPHIER_PIN_DRV_4_8,
+                            295, UNIPHIER_PIN_DRV_1BIT,
                             295, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(312, "PORT14", UNIPHIER_PIN_IECTRL_NONE,
-                            296, UNIPHIER_PIN_DRV_4_8,
+                            296, UNIPHIER_PIN_DRV_1BIT,
                             296, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(313, "PORT15", UNIPHIER_PIN_IECTRL_NONE,
-                            297, UNIPHIER_PIN_DRV_4_8,
+                            297, UNIPHIER_PIN_DRV_1BIT,
                             297, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(314, "PORT16", UNIPHIER_PIN_IECTRL_NONE,
-                            298, UNIPHIER_PIN_DRV_4_8,
+                            298, UNIPHIER_PIN_DRV_1BIT,
                             298, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(315, "PORT17", UNIPHIER_PIN_IECTRL_NONE,
-                            299, UNIPHIER_PIN_DRV_4_8,
+                            299, UNIPHIER_PIN_DRV_1BIT,
                             299, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(316, "PORT20", UNIPHIER_PIN_IECTRL_NONE,
-                            300, UNIPHIER_PIN_DRV_4_8,
+                            300, UNIPHIER_PIN_DRV_1BIT,
                             300, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(317, "PORT21", UNIPHIER_PIN_IECTRL_NONE,
-                            301, UNIPHIER_PIN_DRV_4_8,
+                            301, UNIPHIER_PIN_DRV_1BIT,
                             301, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(318, "PORT22", UNIPHIER_PIN_IECTRL_NONE,
-                            302, UNIPHIER_PIN_DRV_4_8,
+                            302, UNIPHIER_PIN_DRV_1BIT,
                             302, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(319, "SD1DAT0", UNIPHIER_PIN_IECTRL_NONE,
-                            303, UNIPHIER_PIN_DRV_4_8,
+                            303, UNIPHIER_PIN_DRV_1BIT,
                             303, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(320, "SD1DAT1", UNIPHIER_PIN_IECTRL_NONE,
-                            304, UNIPHIER_PIN_DRV_4_8,
+                            304, UNIPHIER_PIN_DRV_1BIT,
                             304, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(321, "SD1DAT2", UNIPHIER_PIN_IECTRL_NONE,
-                            305, UNIPHIER_PIN_DRV_4_8,
+                            305, UNIPHIER_PIN_DRV_1BIT,
                             305, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(322, "SD1DAT3", UNIPHIER_PIN_IECTRL_NONE,
-                            306, UNIPHIER_PIN_DRV_4_8,
+                            306, UNIPHIER_PIN_DRV_1BIT,
                             306, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(323, "SD1CMD", UNIPHIER_PIN_IECTRL_NONE,
-                            307, UNIPHIER_PIN_DRV_4_8,
+                            307, UNIPHIER_PIN_DRV_1BIT,
                             307, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(324, "SD1CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            308, UNIPHIER_PIN_DRV_4_8,
+                            308, UNIPHIER_PIN_DRV_1BIT,
                             308, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(325, "SD1CD", UNIPHIER_PIN_IECTRL_NONE,
-                            309, UNIPHIER_PIN_DRV_4_8,
+                            309, UNIPHIER_PIN_DRV_1BIT,
                             309, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(326, "SD1WP", UNIPHIER_PIN_IECTRL_NONE,
-                            310, UNIPHIER_PIN_DRV_4_8,
+                            310, UNIPHIER_PIN_DRV_1BIT,
                             310, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(327, "SD1VTCG", UNIPHIER_PIN_IECTRL_NONE,
-                            311, UNIPHIER_PIN_DRV_4_8,
+                            311, UNIPHIER_PIN_DRV_1BIT,
                             311, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(328, "DMDISO", UNIPHIER_PIN_IECTRL_NONE,
-                            312, UNIPHIER_PIN_DRV_NONE,
+                            -1, UNIPHIER_PIN_DRV_NONE,
                             312, UNIPHIER_PIN_PULL_DOWN),
 };
 
 static const unsigned emmc_pins[] = {40, 41, 42, 43, 51, 52, 53};
-static const unsigned emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1};
+static const int emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1};
 static const unsigned emmc_dat8_pins[] = {44, 45, 46, 47};
-static const unsigned emmc_dat8_muxvals[] = {1, 1, 1, 1};
+static const int emmc_dat8_muxvals[] = {1, 1, 1, 1};
+static const unsigned ether_mii_pins[] = {160, 161, 162, 163, 164, 165, 166,
+                                         167, 168, 169, 170, 171, 172, 173,
+                                         174, 175, 176, 177, 178, 179};
+static const int ether_mii_muxvals[] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                       0, 0, 0, 0, 0, 0, 0};
+static const unsigned ether_rgmii_pins[] = {160, 161, 162, 163, 164, 165, 167,
+                                           168, 169, 170, 171, 172, 176, 177,
+                                           178, 179};
+static const int ether_rgmii_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                         0, 0, 0, 0};
+static const unsigned ether_rmii_pins[] = {160, 161, 162, 165, 168, 169, 172,
+                                          173, 176, 177, 178, 179};
+static const int ether_rmii_muxvals[] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned ether_rmiib_pins[] = {161, 162, 165, 167, 168, 169, 172,
+                                           173, 176, 177, 178, 179};
+static const int ether_rmiib_muxvals[] = {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0};
 static const unsigned i2c0_pins[] = {142, 143};
-static const unsigned i2c0_muxvals[] = {0, 0};
+static const int i2c0_muxvals[] = {0, 0};
 static const unsigned i2c1_pins[] = {144, 145};
-static const unsigned i2c1_muxvals[] = {0, 0};
+static const int i2c1_muxvals[] = {0, 0};
 static const unsigned i2c2_pins[] = {146, 147};
-static const unsigned i2c2_muxvals[] = {0, 0};
+static const int i2c2_muxvals[] = {0, 0};
 static const unsigned i2c3_pins[] = {148, 149};
-static const unsigned i2c3_muxvals[] = {0, 0};
+static const int i2c3_muxvals[] = {0, 0};
 static const unsigned i2c6_pins[] = {308, 309};
-static const unsigned i2c6_muxvals[] = {6, 6};
+static const int i2c6_muxvals[] = {6, 6};
 static const unsigned nand_pins[] = {40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
                                     50, 51, 52, 53, 54};
-static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                                       0, 0};
+static const int nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 static const unsigned nand_cs1_pins[] = {131, 132};
-static const unsigned nand_cs1_muxvals[] = {1, 1};
+static const int nand_cs1_muxvals[] = {1, 1};
 static const unsigned sd_pins[] = {150, 151, 152, 153, 154, 155, 156, 157, 158};
-static const unsigned sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const int sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
 static const unsigned sd1_pins[] = {319, 320, 321, 322, 323, 324, 325, 326,
                                    327};
-static const unsigned sd1_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const int sd1_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned system_bus_pins[] = {25, 26, 27, 28, 29, 30, 31, 32, 33,
+                                          34, 35, 36, 37, 38};
+static const int system_bus_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                        0};
+static const unsigned system_bus_cs0_pins[] = {318};
+static const int system_bus_cs0_muxvals[] = {5};
+static const unsigned system_bus_cs1_pins[] = {24};
+static const int system_bus_cs1_muxvals[] = {0};
+static const unsigned system_bus_cs2_pins[] = {315};
+static const int system_bus_cs2_muxvals[] = {5};
+static const unsigned system_bus_cs3_pins[] = {313};
+static const int system_bus_cs3_muxvals[] = {5};
+static const unsigned system_bus_cs4_pins[] = {305};
+static const int system_bus_cs4_muxvals[] = {5};
+static const unsigned system_bus_cs5_pins[] = {303};
+static const int system_bus_cs5_muxvals[] = {6};
+static const unsigned system_bus_cs6_pins[] = {307};
+static const int system_bus_cs6_muxvals[] = {6};
+static const unsigned system_bus_cs7_pins[] = {312};
+static const int system_bus_cs7_muxvals[] = {6};
 static const unsigned uart0_pins[] = {127, 128};
-static const unsigned uart0_muxvals[] = {0, 0};
+static const int uart0_muxvals[] = {0, 0};
 static const unsigned uart1_pins[] = {129, 130};
-static const unsigned uart1_muxvals[] = {0, 0};
+static const int uart1_muxvals[] = {0, 0};
 static const unsigned uart2_pins[] = {131, 132};
-static const unsigned uart2_muxvals[] = {0, 0};
+static const int uart2_muxvals[] = {0, 0};
 static const unsigned uart3_pins[] = {88, 89};
-static const unsigned uart3_muxvals[] = {2, 2};
+static const int uart3_muxvals[] = {2, 2};
 static const unsigned usb0_pins[] = {180, 181};
-static const unsigned usb0_muxvals[] = {0, 0};
+static const int usb0_muxvals[] = {0, 0};
 static const unsigned usb1_pins[] = {182, 183};
-static const unsigned usb1_muxvals[] = {0, 0};
+static const int usb1_muxvals[] = {0, 0};
 static const unsigned usb2_pins[] = {184, 185};
-static const unsigned usb2_muxvals[] = {0, 0};
+static const int usb2_muxvals[] = {0, 0};
 static const unsigned usb3_pins[] = {186, 187};
-static const unsigned usb3_muxvals[] = {0, 0};
+static const int usb3_muxvals[] = {0, 0};
 static const unsigned port_range0_pins[] = {
        300, 301, 302, 303, 304, 305, 306, 307,         /* PORT0x */
        308, 309, 310, 311, 312, 313, 314, 315,         /* PORT1x */
@@ -1069,7 +1102,7 @@ static const unsigned port_range0_pins[] = {
        76, 77, 78, 79, 80, 81, 82, 83,                 /* PORT13x */
        84, 85, 86, 87, 88, 89, 90, 91,                 /* PORT14x */
 };
-static const unsigned port_range0_muxvals[] = {
+static const int port_range0_muxvals[] = {
        7, 7, 7, 7, 7, 7, 7, 7,                         /* PORT0x */
        7, 7, 7, 7, 7, 7, 7, 7,                         /* PORT1x */
        7, 7, 7, 7, 7, 7, 7, 7,                         /* PORT2x */
@@ -1102,7 +1135,7 @@ static const unsigned port_range1_pins[] = {
        251, 252, 261, 262, 263, 264, 273, 274,         /* PORT29x */
        31, 32, 33, 34, 35, 36, 37, 38,                 /* PORT30x */
 };
-static const unsigned port_range1_muxvals[] = {
+static const int port_range1_muxvals[] = {
        7, 7, 7,                                        /* PORT175-177 */
        7, 7, 7, 7, 7, 7, 7, 7,                         /* PORT18x */
        7, 7, 7, 7, 7, 7, 7, 7,                         /* PORT19x */
@@ -1123,7 +1156,7 @@ static const unsigned xirq_pins[] = {
        234, 186, 99, 100, 101, 102, 184, 301,          /* XIRQ8-15 */
        302, 303, 304, 305, 306,                        /* XIRQ16-20 */
 };
-static const unsigned xirq_muxvals[] = {
+static const int xirq_muxvals[] = {
        7, 7, 7, 7, 7, 7, 7, 7,                         /* XIRQ0-7 */
        7, 7, 7, 7, 7, 7, 2, 2,                         /* XIRQ8-15 */
        2, 2, 2, 2, 2,                                  /* XIRQ16-20 */
@@ -1131,13 +1164,17 @@ static const unsigned xirq_muxvals[] = {
 static const unsigned xirq_alternatives_pins[] = {
        184, 310, 316,
 };
-static const unsigned xirq_alternatives_muxvals[] = {
+static const int xirq_alternatives_muxvals[] = {
        2, 2, 2,
 };
 
-static const struct uniphier_pinctrl_group ph1_pro4_groups[] = {
+static const struct uniphier_pinctrl_group uniphier_pro4_groups[] = {
        UNIPHIER_PINCTRL_GROUP(emmc),
        UNIPHIER_PINCTRL_GROUP(emmc_dat8),
+       UNIPHIER_PINCTRL_GROUP(ether_mii),
+       UNIPHIER_PINCTRL_GROUP(ether_rgmii),
+       UNIPHIER_PINCTRL_GROUP(ether_rmii),
+       UNIPHIER_PINCTRL_GROUP(ether_rmiib),
        UNIPHIER_PINCTRL_GROUP(i2c0),
        UNIPHIER_PINCTRL_GROUP(i2c1),
        UNIPHIER_PINCTRL_GROUP(i2c2),
@@ -1147,6 +1184,15 @@ static const struct uniphier_pinctrl_group ph1_pro4_groups[] = {
        UNIPHIER_PINCTRL_GROUP(nand_cs1),
        UNIPHIER_PINCTRL_GROUP(sd),
        UNIPHIER_PINCTRL_GROUP(sd1),
+       UNIPHIER_PINCTRL_GROUP(system_bus),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs0),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs1),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs2),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs3),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs4),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs5),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs6),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs7),
        UNIPHIER_PINCTRL_GROUP(uart0),
        UNIPHIER_PINCTRL_GROUP(uart1),
        UNIPHIER_PINCTRL_GROUP(uart2),
@@ -1413,6 +1459,9 @@ static const struct uniphier_pinctrl_group ph1_pro4_groups[] = {
 };
 
 static const char * const emmc_groups[] = {"emmc", "emmc_dat8"};
+static const char * const ether_mii_groups[] = {"ether_mii"};
+static const char * const ether_rgmii_groups[] = {"ether_rgmii"};
+static const char * const ether_rmii_groups[] = {"ether_rgmii", "ether_rgmiib"};
 static const char * const i2c0_groups[] = {"i2c0"};
 static const char * const i2c1_groups[] = {"i2c1"};
 static const char * const i2c2_groups[] = {"i2c2"};
@@ -1421,6 +1470,15 @@ static const char * const i2c6_groups[] = {"i2c6"};
 static const char * const nand_groups[] = {"nand", "nand_cs1"};
 static const char * const sd_groups[] = {"sd"};
 static const char * const sd1_groups[] = {"sd1"};
+static const char * const system_bus_groups[] = {"system_bus",
+                                                "system_bus_cs0",
+                                                "system_bus_cs1",
+                                                "system_bus_cs2",
+                                                "system_bus_cs3",
+                                                "system_bus_cs4",
+                                                "system_bus_cs5",
+                                                "system_bus_cs6",
+                                                "system_bus_cs7"};
 static const char * const uart0_groups[] = {"uart0"};
 static const char * const uart1_groups[] = {"uart1"};
 static const char * const uart2_groups[] = {"uart2"};
@@ -1499,8 +1557,11 @@ static const char * const xirq_groups[] = {
        "xirq14b", "xirq17b", "xirq18b",
 };
 
-static const struct uniphier_pinmux_function ph1_pro4_functions[] = {
+static const struct uniphier_pinmux_function uniphier_pro4_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(emmc),
+       UNIPHIER_PINMUX_FUNCTION(ether_mii),
+       UNIPHIER_PINMUX_FUNCTION(ether_rgmii),
+       UNIPHIER_PINMUX_FUNCTION(ether_rmii),
        UNIPHIER_PINMUX_FUNCTION(i2c0),
        UNIPHIER_PINMUX_FUNCTION(i2c1),
        UNIPHIER_PINMUX_FUNCTION(i2c2),
@@ -1509,6 +1570,7 @@ static const struct uniphier_pinmux_function ph1_pro4_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(nand),
        UNIPHIER_PINMUX_FUNCTION(sd),
        UNIPHIER_PINMUX_FUNCTION(sd1),
+       UNIPHIER_PINMUX_FUNCTION(system_bus),
        UNIPHIER_PINMUX_FUNCTION(uart0),
        UNIPHIER_PINMUX_FUNCTION(uart1),
        UNIPHIER_PINMUX_FUNCTION(uart2),
@@ -1521,43 +1583,36 @@ static const struct uniphier_pinmux_function ph1_pro4_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(xirq),
 };
 
-static struct uniphier_pinctrl_socdata ph1_pro4_pindata = {
-       .groups = ph1_pro4_groups,
-       .groups_count = ARRAY_SIZE(ph1_pro4_groups),
-       .functions = ph1_pro4_functions,
-       .functions_count = ARRAY_SIZE(ph1_pro4_functions),
-       .mux_bits = 4,
-       .reg_stride = 8,
-       .load_pinctrl = true,
-};
-
-static struct pinctrl_desc ph1_pro4_pinctrl_desc = {
-       .name = DRIVER_NAME,
-       .pins = ph1_pro4_pins,
-       .npins = ARRAY_SIZE(ph1_pro4_pins),
-       .owner = THIS_MODULE,
+static struct uniphier_pinctrl_socdata uniphier_pro4_pindata = {
+       .pins = uniphier_pro4_pins,
+       .npins = ARRAY_SIZE(uniphier_pro4_pins),
+       .groups = uniphier_pro4_groups,
+       .groups_count = ARRAY_SIZE(uniphier_pro4_groups),
+       .functions = uniphier_pro4_functions,
+       .functions_count = ARRAY_SIZE(uniphier_pro4_functions),
+       .caps = UNIPHIER_PINCTRL_CAPS_DBGMUX_SEPARATE,
 };
 
-static int ph1_pro4_pinctrl_probe(struct platform_device *pdev)
+static int uniphier_pro4_pinctrl_probe(struct platform_device *pdev)
 {
-       return uniphier_pinctrl_probe(pdev, &ph1_pro4_pinctrl_desc,
-                                     &ph1_pro4_pindata);
+       return uniphier_pinctrl_probe(pdev, &uniphier_pro4_pindata);
 }
 
-static const struct of_device_id ph1_pro4_pinctrl_match[] = {
+static const struct of_device_id uniphier_pro4_pinctrl_match[] = {
+       { .compatible = "socionext,uniphier-pro4-pinctrl" },
        { .compatible = "socionext,ph1-pro4-pinctrl" },
        { /* sentinel */ }
 };
-MODULE_DEVICE_TABLE(of, ph1_pro4_pinctrl_match);
+MODULE_DEVICE_TABLE(of, uniphier_pro4_pinctrl_match);
 
-static struct platform_driver ph1_pro4_pinctrl_driver = {
-       .probe = ph1_pro4_pinctrl_probe,
+static struct platform_driver uniphier_pro4_pinctrl_driver = {
+       .probe = uniphier_pro4_pinctrl_probe,
        .driver = {
-               .name = DRIVER_NAME,
-               .of_match_table = ph1_pro4_pinctrl_match,
+               .name = "uniphier-pro4-pinctrl",
+               .of_match_table = uniphier_pro4_pinctrl_match,
        },
 };
-module_platform_driver(ph1_pro4_pinctrl_driver);
+module_platform_driver(uniphier_pro4_pinctrl_driver);
 
 MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
 MODULE_DESCRIPTION("UniPhier PH1-Pro4 pinctrl driver");
index 3087f76..55d4a12 100644 (file)
 
 #include "pinctrl-uniphier.h"
 
-#define DRIVER_NAME "ph1-pro5-pinctrl"
-
-static const struct pinctrl_pin_desc ph1_pro5_pins[] = {
+static const struct pinctrl_pin_desc uniphier_pro5_pins[] = {
        UNIPHIER_PINCTRL_PIN(0, "AEXCKA1", 0,
-                            0, UNIPHIER_PIN_DRV_4_8,
+                            0, UNIPHIER_PIN_DRV_1BIT,
                             0, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(1, "AEXCKA2", 0,
-                            1, UNIPHIER_PIN_DRV_4_8,
+                            1, UNIPHIER_PIN_DRV_1BIT,
                             1, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(2, "CK27EXI", 0,
-                            2, UNIPHIER_PIN_DRV_4_8,
+                            2, UNIPHIER_PIN_DRV_1BIT,
                             2, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(3, "CK54EXI", 0,
-                            3, UNIPHIER_PIN_DRV_4_8,
+                            3, UNIPHIER_PIN_DRV_1BIT,
                             3, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(4, "ED0", UNIPHIER_PIN_IECTRL_NONE,
-                            4, UNIPHIER_PIN_DRV_4_8,
+                            4, UNIPHIER_PIN_DRV_1BIT,
                             4, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(5, "ED1", UNIPHIER_PIN_IECTRL_NONE,
-                            5, UNIPHIER_PIN_DRV_4_8,
+                            5, UNIPHIER_PIN_DRV_1BIT,
                             5, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(6, "ED2", UNIPHIER_PIN_IECTRL_NONE,
-                            6, UNIPHIER_PIN_DRV_4_8,
+                            6, UNIPHIER_PIN_DRV_1BIT,
                             6, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(7, "ED3", UNIPHIER_PIN_IECTRL_NONE,
-                            7, UNIPHIER_PIN_DRV_4_8,
+                            7, UNIPHIER_PIN_DRV_1BIT,
                             7, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(8, "ED4", UNIPHIER_PIN_IECTRL_NONE,
-                            8, UNIPHIER_PIN_DRV_4_8,
+                            8, UNIPHIER_PIN_DRV_1BIT,
                             8, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(9, "ED5", UNIPHIER_PIN_IECTRL_NONE,
-                            9, UNIPHIER_PIN_DRV_4_8,
+                            9, UNIPHIER_PIN_DRV_1BIT,
                             9, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(10, "ED6", UNIPHIER_PIN_IECTRL_NONE,
-                            10, UNIPHIER_PIN_DRV_4_8,
+                            10, UNIPHIER_PIN_DRV_1BIT,
                             10, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(11, "ED7", UNIPHIER_PIN_IECTRL_NONE,
-                            11, UNIPHIER_PIN_DRV_4_8,
+                            11, UNIPHIER_PIN_DRV_1BIT,
                             11, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(12, "XERWE0", UNIPHIER_PIN_IECTRL_NONE,
-                            12, UNIPHIER_PIN_DRV_4_8,
+                            12, UNIPHIER_PIN_DRV_1BIT,
                             12, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(13, "XERWE1", UNIPHIER_PIN_IECTRL_NONE,
-                            13, UNIPHIER_PIN_DRV_4_8,
+                            13, UNIPHIER_PIN_DRV_1BIT,
                             13, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(14, "ERXW", UNIPHIER_PIN_IECTRL_NONE,
-                            14, UNIPHIER_PIN_DRV_4_8,
+                            14, UNIPHIER_PIN_DRV_1BIT,
                             14, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(15, "ES0", UNIPHIER_PIN_IECTRL_NONE,
-                            15, UNIPHIER_PIN_DRV_4_8,
+                            15, UNIPHIER_PIN_DRV_1BIT,
                             15, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(16, "ES1", UNIPHIER_PIN_IECTRL_NONE,
-                            16, UNIPHIER_PIN_DRV_4_8,
+                            16, UNIPHIER_PIN_DRV_1BIT,
                             16, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(17, "ES2", UNIPHIER_PIN_IECTRL_NONE,
-                            17, UNIPHIER_PIN_DRV_4_8,
+                            17, UNIPHIER_PIN_DRV_1BIT,
                             17, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(18, "XECS1", UNIPHIER_PIN_IECTRL_NONE,
-                            18, UNIPHIER_PIN_DRV_4_8,
+                            18, UNIPHIER_PIN_DRV_1BIT,
                             18, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(19, "XNFRE", UNIPHIER_PIN_IECTRL_NONE,
-                            19, UNIPHIER_PIN_DRV_4_8,
+                            19, UNIPHIER_PIN_DRV_1BIT,
                             19, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(20, "XNFWE", UNIPHIER_PIN_IECTRL_NONE,
-                            20, UNIPHIER_PIN_DRV_4_8,
+                            20, UNIPHIER_PIN_DRV_1BIT,
                             20, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(21, "NFALE", UNIPHIER_PIN_IECTRL_NONE,
-                            21, UNIPHIER_PIN_DRV_4_8,
+                            21, UNIPHIER_PIN_DRV_1BIT,
                             21, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(22, "NFCLE", UNIPHIER_PIN_IECTRL_NONE,
-                            22, UNIPHIER_PIN_DRV_4_8,
+                            22, UNIPHIER_PIN_DRV_1BIT,
                             22, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(23, "XNFWP", UNIPHIER_PIN_IECTRL_NONE,
-                            23, UNIPHIER_PIN_DRV_4_8,
+                            23, UNIPHIER_PIN_DRV_1BIT,
                             23, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(24, "XNFCE0", UNIPHIER_PIN_IECTRL_NONE,
-                            24, UNIPHIER_PIN_DRV_4_8,
+                            24, UNIPHIER_PIN_DRV_1BIT,
                             24, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(25, "NFRYBY0", UNIPHIER_PIN_IECTRL_NONE,
-                            25, UNIPHIER_PIN_DRV_4_8,
+                            25, UNIPHIER_PIN_DRV_1BIT,
                             25, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(26, "XNFCE1", UNIPHIER_PIN_IECTRL_NONE,
-                            26, UNIPHIER_PIN_DRV_4_8,
+                            26, UNIPHIER_PIN_DRV_1BIT,
                             26, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(27, "NFRYBY1", UNIPHIER_PIN_IECTRL_NONE,
-                            27, UNIPHIER_PIN_DRV_4_8,
+                            27, UNIPHIER_PIN_DRV_1BIT,
                             27, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(28, "NFD0", UNIPHIER_PIN_IECTRL_NONE,
-                            28, UNIPHIER_PIN_DRV_4_8,
+                            28, UNIPHIER_PIN_DRV_1BIT,
                             28, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(29, "NFD1", UNIPHIER_PIN_IECTRL_NONE,
-                            29, UNIPHIER_PIN_DRV_4_8,
+                            29, UNIPHIER_PIN_DRV_1BIT,
                             29, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(30, "NFD2", UNIPHIER_PIN_IECTRL_NONE,
-                            30, UNIPHIER_PIN_DRV_4_8,
+                            30, UNIPHIER_PIN_DRV_1BIT,
                             30, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(31, "NFD3", UNIPHIER_PIN_IECTRL_NONE,
-                            31, UNIPHIER_PIN_DRV_4_8,
+                            31, UNIPHIER_PIN_DRV_1BIT,
                             31, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(32, "NFD4", UNIPHIER_PIN_IECTRL_NONE,
-                            32, UNIPHIER_PIN_DRV_4_8,
+                            32, UNIPHIER_PIN_DRV_1BIT,
                             32, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(33, "NFD5", UNIPHIER_PIN_IECTRL_NONE,
-                            33, UNIPHIER_PIN_DRV_4_8,
+                            33, UNIPHIER_PIN_DRV_1BIT,
                             33, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(34, "NFD6", UNIPHIER_PIN_IECTRL_NONE,
-                            34, UNIPHIER_PIN_DRV_4_8,
+                            34, UNIPHIER_PIN_DRV_1BIT,
                             34, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(35, "NFD7", UNIPHIER_PIN_IECTRL_NONE,
-                            35, UNIPHIER_PIN_DRV_4_8,
+                            35, UNIPHIER_PIN_DRV_1BIT,
                             35, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(36, "XERST", UNIPHIER_PIN_IECTRL_NONE,
-                            36, UNIPHIER_PIN_DRV_4_8,
+                            36, UNIPHIER_PIN_DRV_1BIT,
                             36, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(37, "MMCCLK", UNIPHIER_PIN_IECTRL_NONE,
-                            37, UNIPHIER_PIN_DRV_4_8,
+                            37, UNIPHIER_PIN_DRV_1BIT,
                             37, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(38, "MMCCMD", UNIPHIER_PIN_IECTRL_NONE,
-                            38, UNIPHIER_PIN_DRV_4_8,
+                            38, UNIPHIER_PIN_DRV_1BIT,
                             38, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(39, "MMCDAT0", UNIPHIER_PIN_IECTRL_NONE,
-                            39, UNIPHIER_PIN_DRV_4_8,
+                            39, UNIPHIER_PIN_DRV_1BIT,
                             39, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(40, "MMCDAT1", UNIPHIER_PIN_IECTRL_NONE,
-                            40, UNIPHIER_PIN_DRV_4_8,
+                            40, UNIPHIER_PIN_DRV_1BIT,
                             40, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(41, "MMCDAT2", UNIPHIER_PIN_IECTRL_NONE,
-                            41, UNIPHIER_PIN_DRV_4_8,
+                            41, UNIPHIER_PIN_DRV_1BIT,
                             41, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(42, "MMCDAT3", UNIPHIER_PIN_IECTRL_NONE,
-                            42, UNIPHIER_PIN_DRV_4_8,
+                            42, UNIPHIER_PIN_DRV_1BIT,
                             42, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(43, "MMCDAT4", UNIPHIER_PIN_IECTRL_NONE,
-                            43, UNIPHIER_PIN_DRV_4_8,
+                            43, UNIPHIER_PIN_DRV_1BIT,
                             43, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(44, "MMCDAT5", UNIPHIER_PIN_IECTRL_NONE,
-                            44, UNIPHIER_PIN_DRV_4_8,
+                            44, UNIPHIER_PIN_DRV_1BIT,
                             44, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(45, "MMCDAT6", UNIPHIER_PIN_IECTRL_NONE,
-                            45, UNIPHIER_PIN_DRV_4_8,
+                            45, UNIPHIER_PIN_DRV_1BIT,
                             45, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(46, "MMCDAT7", UNIPHIER_PIN_IECTRL_NONE,
-                            46, UNIPHIER_PIN_DRV_4_8,
+                            46, UNIPHIER_PIN_DRV_1BIT,
                             46, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(47, "TXD0", 0,
-                            47, UNIPHIER_PIN_DRV_4_8,
+                            47, UNIPHIER_PIN_DRV_1BIT,
                             47, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(48, "RXD0", 0,
-                            48, UNIPHIER_PIN_DRV_4_8,
+                            48, UNIPHIER_PIN_DRV_1BIT,
                             48, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(49, "TXD1", 0,
-                            49, UNIPHIER_PIN_DRV_4_8,
+                            49, UNIPHIER_PIN_DRV_1BIT,
                             49, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(50, "RXD1", 0,
-                            50, UNIPHIER_PIN_DRV_4_8,
+                            50, UNIPHIER_PIN_DRV_1BIT,
                             50, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(51, "TXD2", UNIPHIER_PIN_IECTRL_NONE,
-                            51, UNIPHIER_PIN_DRV_4_8,
+                            51, UNIPHIER_PIN_DRV_1BIT,
                             51, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(52, "RXD2", UNIPHIER_PIN_IECTRL_NONE,
-                            52, UNIPHIER_PIN_DRV_4_8,
+                            52, UNIPHIER_PIN_DRV_1BIT,
                             52, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(53, "TXD3", 0,
-                            53, UNIPHIER_PIN_DRV_4_8,
+                            53, UNIPHIER_PIN_DRV_1BIT,
                             53, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(54, "RXD3", 0,
-                            54, UNIPHIER_PIN_DRV_4_8,
+                            54, UNIPHIER_PIN_DRV_1BIT,
                             54, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(55, "MS0CS0", 0,
-                            55, UNIPHIER_PIN_DRV_4_8,
+                            55, UNIPHIER_PIN_DRV_1BIT,
                             55, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(56, "MS0DO", 0,
-                            56, UNIPHIER_PIN_DRV_4_8,
+                            56, UNIPHIER_PIN_DRV_1BIT,
                             56, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(57, "MS0DI", 0,
-                            57, UNIPHIER_PIN_DRV_4_8,
+                            57, UNIPHIER_PIN_DRV_1BIT,
                             57, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(58, "MS0CLK", 0,
-                            58, UNIPHIER_PIN_DRV_4_8,
+                            58, UNIPHIER_PIN_DRV_1BIT,
                             58, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(59, "CSCLK", 0,
-                            59, UNIPHIER_PIN_DRV_4_8,
+                            59, UNIPHIER_PIN_DRV_1BIT,
                             59, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(60, "CSBPTM", 0,
-                            60, UNIPHIER_PIN_DRV_4_8,
+                            60, UNIPHIER_PIN_DRV_1BIT,
                             60, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(61, "CSBMTP", 0,
-                            61, UNIPHIER_PIN_DRV_4_8,
+                            61, UNIPHIER_PIN_DRV_1BIT,
                             61, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(62, "XCINTP", 0,
-                            62, UNIPHIER_PIN_DRV_4_8,
+                            62, UNIPHIER_PIN_DRV_1BIT,
                             62, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(63, "XCINTM", 0,
-                            63, UNIPHIER_PIN_DRV_4_8,
+                            63, UNIPHIER_PIN_DRV_1BIT,
                             63, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(64, "XCMPREQ", 0,
-                            64, UNIPHIER_PIN_DRV_4_8,
+                            64, UNIPHIER_PIN_DRV_1BIT,
                             64, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(65, "XSRST", 0,
-                            65, UNIPHIER_PIN_DRV_4_8,
+                            65, UNIPHIER_PIN_DRV_1BIT,
                             65, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(66, "LPST", UNIPHIER_PIN_IECTRL_NONE,
-                            66, UNIPHIER_PIN_DRV_4_8,
+                            66, UNIPHIER_PIN_DRV_1BIT,
                             66, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(67, "PWMA", 0,
-                            67, UNIPHIER_PIN_DRV_4_8,
+                            67, UNIPHIER_PIN_DRV_1BIT,
                             67, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(68, "XIRQ0", 0,
-                            68, UNIPHIER_PIN_DRV_4_8,
+                            68, UNIPHIER_PIN_DRV_1BIT,
                             68, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(69, "XIRQ1", 0,
-                            69, UNIPHIER_PIN_DRV_4_8,
+                            69, UNIPHIER_PIN_DRV_1BIT,
                             69, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(70, "XIRQ2", 0,
-                            70, UNIPHIER_PIN_DRV_4_8,
+                            70, UNIPHIER_PIN_DRV_1BIT,
                             70, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(71, "XIRQ3", 0,
-                            71, UNIPHIER_PIN_DRV_4_8,
+                            71, UNIPHIER_PIN_DRV_1BIT,
                             71, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(72, "XIRQ4", 0,
-                            72, UNIPHIER_PIN_DRV_4_8,
+                            72, UNIPHIER_PIN_DRV_1BIT,
                             72, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(73, "XIRQ5", 0,
-                            73, UNIPHIER_PIN_DRV_4_8,
+                            73, UNIPHIER_PIN_DRV_1BIT,
                             73, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(74, "XIRQ6", 0,
-                            74, UNIPHIER_PIN_DRV_4_8,
+                            74, UNIPHIER_PIN_DRV_1BIT,
                             74, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(75, "XIRQ7", 0,
-                            75, UNIPHIER_PIN_DRV_4_8,
+                            75, UNIPHIER_PIN_DRV_1BIT,
                             75, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(76, "XIRQ8", 0,
-                            76, UNIPHIER_PIN_DRV_4_8,
+                            76, UNIPHIER_PIN_DRV_1BIT,
                             76, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(77, "XIRQ9", 0,
-                            77, UNIPHIER_PIN_DRV_4_8,
+                            77, UNIPHIER_PIN_DRV_1BIT,
                             77, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(78, "XIRQ10", 0,
-                            78, UNIPHIER_PIN_DRV_4_8,
+                            78, UNIPHIER_PIN_DRV_1BIT,
                             78, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(79, "XIRQ11", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             79, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(80, "XIRQ12", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             80, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(81, "XIRQ13", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             81, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(82, "XIRQ14", 0,
-                            82, UNIPHIER_PIN_DRV_4_8,
+                            82, UNIPHIER_PIN_DRV_1BIT,
                             82, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(83, "XIRQ15", 0,
-                            83, UNIPHIER_PIN_DRV_4_8,
+                            83, UNIPHIER_PIN_DRV_1BIT,
                             83, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(84, "XIRQ16", 0,
-                            84, UNIPHIER_PIN_DRV_4_8,
+                            84, UNIPHIER_PIN_DRV_1BIT,
                             84, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(85, "XIRQ17", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             85, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(86, "XIRQ18", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             86, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(87, "XIRQ19", 0,
-                            87, UNIPHIER_PIN_DRV_4_8,
+                            87, UNIPHIER_PIN_DRV_1BIT,
                             87, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(88, "XIRQ20", 0,
-                            88, UNIPHIER_PIN_DRV_4_8,
+                            88, UNIPHIER_PIN_DRV_1BIT,
                             88, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(89, "PORT00", 0,
-                            89, UNIPHIER_PIN_DRV_4_8,
+                            89, UNIPHIER_PIN_DRV_1BIT,
                             89, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(90, "PORT01", 0,
-                            90, UNIPHIER_PIN_DRV_4_8,
+                            90, UNIPHIER_PIN_DRV_1BIT,
                             90, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(91, "PORT02", 0,
-                            91, UNIPHIER_PIN_DRV_4_8,
+                            91, UNIPHIER_PIN_DRV_1BIT,
                             91, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(92, "PORT03", 0,
-                            92, UNIPHIER_PIN_DRV_4_8,
+                            92, UNIPHIER_PIN_DRV_1BIT,
                             92, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(93, "PORT04", 0,
-                            93, UNIPHIER_PIN_DRV_4_8,
+                            93, UNIPHIER_PIN_DRV_1BIT,
                             93, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(94, "PORT05", 0,
-                            94, UNIPHIER_PIN_DRV_4_8,
+                            94, UNIPHIER_PIN_DRV_1BIT,
                             94, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(95, "PORT06", 0,
-                            95, UNIPHIER_PIN_DRV_4_8,
+                            95, UNIPHIER_PIN_DRV_1BIT,
                             95, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(96, "PORT07", 0,
-                            96, UNIPHIER_PIN_DRV_4_8,
+                            96, UNIPHIER_PIN_DRV_1BIT,
                             96, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(97, "PORT10", 0,
-                            97, UNIPHIER_PIN_DRV_4_8,
+                            97, UNIPHIER_PIN_DRV_1BIT,
                             97, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(98, "PORT11", 0,
-                            98, UNIPHIER_PIN_DRV_4_8,
+                            98, UNIPHIER_PIN_DRV_1BIT,
                             98, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(99, "PORT12", 0,
-                            99, UNIPHIER_PIN_DRV_4_8,
+                            99, UNIPHIER_PIN_DRV_1BIT,
                             99, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(100, "PORT13", 0,
-                            100, UNIPHIER_PIN_DRV_4_8,
+                            100, UNIPHIER_PIN_DRV_1BIT,
                             100, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(101, "PORT14", 0,
-                            101, UNIPHIER_PIN_DRV_4_8,
+                            101, UNIPHIER_PIN_DRV_1BIT,
                             101, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(102, "PORT15", 0,
-                            102, UNIPHIER_PIN_DRV_4_8,
+                            102, UNIPHIER_PIN_DRV_1BIT,
                             102, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(103, "PORT16", 0,
-                            103, UNIPHIER_PIN_DRV_4_8,
+                            103, UNIPHIER_PIN_DRV_1BIT,
                             103, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(104, "PORT17", 0,
-                            104, UNIPHIER_PIN_DRV_4_8,
+                            104, UNIPHIER_PIN_DRV_1BIT,
                             104, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(105, "T0HPD", 0,
-                            105, UNIPHIER_PIN_DRV_4_8,
+                            105, UNIPHIER_PIN_DRV_1BIT,
                             105, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(106, "T1HPD", 0,
-                            106, UNIPHIER_PIN_DRV_4_8,
+                            106, UNIPHIER_PIN_DRV_1BIT,
                             106, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(107, "R0HPD", 0,
-                            107, UNIPHIER_PIN_DRV_4_8,
+                            107, UNIPHIER_PIN_DRV_1BIT,
                             107, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(108, "R1HPD", 0,
-                            108, UNIPHIER_PIN_DRV_4_8,
+                            108, UNIPHIER_PIN_DRV_1BIT,
                             108, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(109, "XPERST", 0,
-                            109, UNIPHIER_PIN_DRV_4_8,
+                            109, UNIPHIER_PIN_DRV_1BIT,
                             109, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(110, "XPEWAKE", 0,
-                            110, UNIPHIER_PIN_DRV_4_8,
+                            110, UNIPHIER_PIN_DRV_1BIT,
                             110, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(111, "XPECLKRQ", 0,
-                            111, UNIPHIER_PIN_DRV_4_8,
+                            111, UNIPHIER_PIN_DRV_1BIT,
                             111, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(112, "SDA0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             112, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(113, "SCL0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             113, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(114, "SDA1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             114, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(115, "SCL1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             115, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(116, "SDA2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             116, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(117, "SCL2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             117, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(118, "SDA3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             118, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(119, "SCL3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             119, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(120, "SPISYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             120, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(121, "SPISCLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             121, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(122, "SPITXD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             122, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(123, "SPIRXD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             123, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(124, "USB0VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             124, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(125, "USB0OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             125, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(126, "USB1VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             126, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(127, "USB1OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             127, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(128, "USB2VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             128, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(129, "USB2OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             129, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(130, "SMTRST0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             130, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(131, "SMTCMD0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             131, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(132, "SMTD0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             132, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(133, "SMTSEL0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             133, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(134, "SMTCLK0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             134, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(135, "SMTRST1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             135, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(136, "SMTCMD1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             136, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(137, "SMTD1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             137, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(138, "SMTSEL1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             138, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(139, "SMTCLK1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             139, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(140, "CH0CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             140, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(141, "CH0PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             141, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(142, "CH0VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             142, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(143, "CH0DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             143, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(144, "CH1CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             144, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(145, "CH1PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             145, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(146, "CH1VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             146, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(147, "CH1DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             147, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(148, "CH2CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             148, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(149, "CH2PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             149, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(150, "CH2VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             150, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(151, "CH2DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             151, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(152, "CH3CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             152, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(153, "CH3PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             153, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(154, "CH3VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             154, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(155, "CH3DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             155, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(156, "CH4CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             156, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(157, "CH4PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             157, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(158, "CH4VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             158, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(159, "CH4DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             159, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(160, "CH5CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             160, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(161, "CH5PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             161, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(162, "CH5VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             162, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(163, "CH5DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             163, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(164, "CH6CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             164, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(165, "CH6PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             165, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(166, "CH6VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             166, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(167, "CH6DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             167, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(168, "CH7CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             168, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(169, "CH7PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             169, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(170, "CH7VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             170, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(171, "CH7DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             171, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(172, "AI1ADCCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             172, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(173, "AI1BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             173, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(174, "AI1LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             174, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(175, "AI1D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             175, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(176, "AI1D1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             176, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(177, "AI1D2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             177, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(178, "AI1D3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             178, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(179, "AI2ADCCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             179, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(180, "AI2BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             180, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(181, "AI2LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             181, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(182, "AI2D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             182, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(183, "AI2D1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             183, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(184, "AI2D2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             184, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(185, "AI2D3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             185, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(186, "AI3ADCCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             186, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(187, "AI3BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             187, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(188, "AI3LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             188, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(189, "AI3D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             189, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(190, "AO1IEC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             190, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(191, "AO1DACCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             191, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(192, "AO1BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             192, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(193, "AO1LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             193, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(194, "AO1D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             194, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(195, "AO1D1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             195, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(196, "AO1D2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             196, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(197, "AO1D3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             197, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(198, "AO2IEC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             198, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(199, "AO2DACCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             199, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(200, "AO2BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             200, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(201, "AO2LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             201, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(202, "AO2D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             202, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(203, "AO2D1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             203, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(204, "AO2D2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             204, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(205, "AO2D3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             205, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(206, "AO3DACCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             206, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(207, "AO3BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             207, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(208, "AO3LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             208, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(209, "AO3DMIX", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             209, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(210, "AO4DACCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             210, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(211, "AO4BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             211, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(212, "AO4LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             212, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(213, "AO4DMIX", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             213, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(214, "VI1CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             214, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(215, "VI1C0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             215, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(216, "VI1C1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             216, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(217, "VI1C2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             217, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(218, "VI1C3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             218, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(219, "VI1C4", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             219, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(220, "VI1C5", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             220, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(221, "VI1C6", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             221, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(222, "VI1C7", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             222, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(223, "VI1C8", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             223, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(224, "VI1C9", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             224, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(225, "VI1Y0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             225, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(226, "VI1Y1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             226, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(227, "VI1Y2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             227, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(228, "VI1Y3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             228, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(229, "VI1Y4", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             229, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(230, "VI1Y5", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             230, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(231, "VI1Y6", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             231, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(232, "VI1Y7", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             232, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(233, "VI1Y8", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             233, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(234, "VI1Y9", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             234, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(235, "VI1DE", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             235, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(236, "VI1HSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             236, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(237, "VI1VSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             237, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(238, "VO1CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             238, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(239, "VO1D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             239, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(240, "VO1D1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             240, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(241, "VO1D2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             241, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(242, "VO1D3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             242, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(243, "VO1D4", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             243, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(244, "VO1D5", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             244, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(245, "VO1D6", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             245, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(246, "VO1D7", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             246, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(247, "SDCD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             247, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(248, "SDWP", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             248, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(249, "SDVOLC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             249, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(250, "SDCLK", UNIPHIER_PIN_IECTRL_NONE,
-                            40, UNIPHIER_PIN_DRV_8_12_16_20,
+                            10, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(251, "SDCMD", UNIPHIER_PIN_IECTRL_NONE,
-                            44, UNIPHIER_PIN_DRV_8_12_16_20,
+                            11, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(252, "SDDAT0", UNIPHIER_PIN_IECTRL_NONE,
-                            48, UNIPHIER_PIN_DRV_8_12_16_20,
+                            12, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(253, "SDDAT1", UNIPHIER_PIN_IECTRL_NONE,
-                            52, UNIPHIER_PIN_DRV_8_12_16_20,
+                            13, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(254, "SDDAT2", UNIPHIER_PIN_IECTRL_NONE,
-                            56, UNIPHIER_PIN_DRV_8_12_16_20,
+                            14, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(255, "SDDAT3", UNIPHIER_PIN_IECTRL_NONE,
-                            60, UNIPHIER_PIN_DRV_8_12_16_20,
+                            15, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
 };
 
 static const unsigned emmc_pins[] = {36, 37, 38, 39, 40, 41, 42};
-static const unsigned emmc_muxvals[] = {0, 0, 0, 0, 0, 0, 0};
+static const int emmc_muxvals[] = {0, 0, 0, 0, 0, 0, 0};
 static const unsigned emmc_dat8_pins[] = {43, 44, 45, 46};
-static const unsigned emmc_dat8_muxvals[] = {0, 0, 0, 0};
+static const int emmc_dat8_muxvals[] = {0, 0, 0, 0};
 static const unsigned i2c0_pins[] = {112, 113};
-static const unsigned i2c0_muxvals[] = {0, 0};
+static const int i2c0_muxvals[] = {0, 0};
 static const unsigned i2c1_pins[] = {114, 115};
-static const unsigned i2c1_muxvals[] = {0, 0};
+static const int i2c1_muxvals[] = {0, 0};
 static const unsigned i2c2_pins[] = {116, 117};
-static const unsigned i2c2_muxvals[] = {0, 0};
+static const int i2c2_muxvals[] = {0, 0};
 static const unsigned i2c3_pins[] = {118, 119};
-static const unsigned i2c3_muxvals[] = {0, 0};
+static const int i2c3_muxvals[] = {0, 0};
 static const unsigned i2c5_pins[] = {87, 88};
-static const unsigned i2c5_muxvals[] = {2, 2};
+static const int i2c5_muxvals[] = {2, 2};
 static const unsigned i2c5b_pins[] = {196, 197};
-static const unsigned i2c5b_muxvals[] = {2, 2};
+static const int i2c5b_muxvals[] = {2, 2};
 static const unsigned i2c5c_pins[] = {215, 216};
-static const unsigned i2c5c_muxvals[] = {2, 2};
+static const int i2c5c_muxvals[] = {2, 2};
 static const unsigned i2c6_pins[] = {101, 102};
-static const unsigned i2c6_muxvals[] = {2, 2};
+static const int i2c6_muxvals[] = {2, 2};
 static const unsigned nand_pins[] = {19, 20, 21, 22, 23, 24, 25, 28, 29, 30,
                                     31, 32, 33, 34, 35};
-static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                                       0, 0};
+static const int nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 static const unsigned nand_cs1_pins[] = {26, 27};
-static const unsigned nand_cs1_muxvals[] = {0, 0};
+static const int nand_cs1_muxvals[] = {0, 0};
 static const unsigned sd_pins[] = {250, 251, 252, 253, 254, 255, 256, 257, 258};
-static const unsigned sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const int sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned system_bus_pins[] = {4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+                                          14, 15, 16, 17};
+static const int system_bus_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                        0};
+static const unsigned system_bus_cs0_pins[] = {105};
+static const int system_bus_cs0_muxvals[] = {1};
+static const unsigned system_bus_cs1_pins[] = {18};
+static const int system_bus_cs1_muxvals[] = {0};
+static const unsigned system_bus_cs2_pins[] = {106};
+static const int system_bus_cs2_muxvals[] = {1};
+static const unsigned system_bus_cs3_pins[] = {100};
+static const int system_bus_cs3_muxvals[] = {1};
+static const unsigned system_bus_cs4_pins[] = {101};
+static const int system_bus_cs4_muxvals[] = {1};
+static const unsigned system_bus_cs5_pins[] = {102};
+static const int system_bus_cs5_muxvals[] = {1};
+static const unsigned system_bus_cs6_pins[] = {69};
+static const int system_bus_cs6_muxvals[] = {5};
+static const unsigned system_bus_cs7_pins[] = {70};
+static const int system_bus_cs7_muxvals[] = {5};
 static const unsigned uart0_pins[] = {47, 48};
-static const unsigned uart0_muxvals[] = {0, 0};
+static const int uart0_muxvals[] = {0, 0};
 static const unsigned uart0b_pins[] = {227, 228};
-static const unsigned uart0b_muxvals[] = {3, 3};
+static const int uart0b_muxvals[] = {3, 3};
 static const unsigned uart1_pins[] = {49, 50};
-static const unsigned uart1_muxvals[] = {0, 0};
+static const int uart1_muxvals[] = {0, 0};
 static const unsigned uart2_pins[] = {51, 52};
-static const unsigned uart2_muxvals[] = {0, 0};
+static const int uart2_muxvals[] = {0, 0};
 static const unsigned uart3_pins[] = {53, 54};
-static const unsigned uart3_muxvals[] = {0, 0};
+static const int uart3_muxvals[] = {0, 0};
 static const unsigned usb0_pins[] = {124, 125};
-static const unsigned usb0_muxvals[] = {0, 0};
+static const int usb0_muxvals[] = {0, 0};
 static const unsigned usb1_pins[] = {126, 127};
-static const unsigned usb1_muxvals[] = {0, 0};
+static const int usb1_muxvals[] = {0, 0};
 static const unsigned usb2_pins[] = {128, 129};
-static const unsigned usb2_muxvals[] = {0, 0};
+static const int usb2_muxvals[] = {0, 0};
 static const unsigned port_range0_pins[] = {
        89, 90, 91, 92, 93, 94, 95, 96,                 /* PORT0x */
        97, 98, 99, 100, 101, 102, 103, 104,            /* PORT1x */
@@ -853,7 +870,7 @@ static const unsigned port_range0_pins[] = {
        179, 180, 181, 182, 186, 187, 188, 189,         /* PORT13x */
        4, 5, 6, 7, 8, 9, 10, 11,                       /* PORT14x */
 };
-static const unsigned port_range0_muxvals[] = {
+static const int port_range0_muxvals[] = {
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT0x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT1x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT2x */
@@ -886,7 +903,7 @@ static const unsigned port_range1_pins[] = {
        105, 106, 18, 27, 36, 128, 132, 137,            /* PORT29x */
        183, 184, 185, 84, 47, 48, 51, 52,              /* PORT30x */
 };
-static const unsigned port_range1_muxvals[] = {
+static const int port_range1_muxvals[] = {
        15, 15, 15,                                     /* PORT175-177 */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT18x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT19x */
@@ -907,7 +924,7 @@ static const unsigned xirq_pins[] = {
        76, 77, 78, 79, 80, 81, 82, 83,                 /* XIRQ8-15 */
        84, 85, 86, 87, 88,                             /* XIRQ16-20 */
 };
-static const unsigned xirq_muxvals[] = {
+static const int xirq_muxvals[] = {
        14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ0-7 */
        14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ8-15 */
        14, 14, 14, 14, 14,                             /* XIRQ16-20 */
@@ -915,11 +932,11 @@ static const unsigned xirq_muxvals[] = {
 static const unsigned xirq_alternatives_pins[] = {
        91, 92, 239, 144, 240, 156, 241, 106, 128,
 };
-static const unsigned xirq_alternatives_muxvals[] = {
+static const int xirq_alternatives_muxvals[] = {
        14, 14, 14, 14, 14, 14, 14, 14, 14,
 };
 
-static const struct uniphier_pinctrl_group ph1_pro5_groups[] = {
+static const struct uniphier_pinctrl_group uniphier_pro5_groups[] = {
        UNIPHIER_PINCTRL_GROUP(nand),
        UNIPHIER_PINCTRL_GROUP(nand_cs1),
        UNIPHIER_PINCTRL_GROUP(emmc),
@@ -933,6 +950,15 @@ static const struct uniphier_pinctrl_group ph1_pro5_groups[] = {
        UNIPHIER_PINCTRL_GROUP(i2c5c),
        UNIPHIER_PINCTRL_GROUP(i2c6),
        UNIPHIER_PINCTRL_GROUP(sd),
+       UNIPHIER_PINCTRL_GROUP(system_bus),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs0),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs1),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs2),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs3),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs4),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs5),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs6),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs7),
        UNIPHIER_PINCTRL_GROUP(uart0),
        UNIPHIER_PINCTRL_GROUP(uart0b),
        UNIPHIER_PINCTRL_GROUP(uart1),
@@ -1213,6 +1239,15 @@ static const char * const i2c5_groups[] = {"i2c5", "i2c5b", "i2c5c"};
 static const char * const i2c6_groups[] = {"i2c6"};
 static const char * const nand_groups[] = {"nand", "nand_cs1"};
 static const char * const sd_groups[] = {"sd"};
+static const char * const system_bus_groups[] = {"system_bus",
+                                                "system_bus_cs0",
+                                                "system_bus_cs1",
+                                                "system_bus_cs2",
+                                                "system_bus_cs3",
+                                                "system_bus_cs4",
+                                                "system_bus_cs5",
+                                                "system_bus_cs6",
+                                                "system_bus_cs7"};
 static const char * const uart0_groups[] = {"uart0", "uart0b"};
 static const char * const uart1_groups[] = {"uart1"};
 static const char * const uart2_groups[] = {"uart2"};
@@ -1291,7 +1326,7 @@ static const char * const xirq_groups[] = {
        "xirq18b", "xirq18c", "xirq19b", "xirq20b",
 };
 
-static const struct uniphier_pinmux_function ph1_pro5_functions[] = {
+static const struct uniphier_pinmux_function uniphier_pro5_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(emmc),
        UNIPHIER_PINMUX_FUNCTION(i2c0),
        UNIPHIER_PINMUX_FUNCTION(i2c1),
@@ -1301,6 +1336,7 @@ static const struct uniphier_pinmux_function ph1_pro5_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(i2c6),
        UNIPHIER_PINMUX_FUNCTION(nand),
        UNIPHIER_PINMUX_FUNCTION(sd),
+       UNIPHIER_PINMUX_FUNCTION(system_bus),
        UNIPHIER_PINMUX_FUNCTION(uart0),
        UNIPHIER_PINMUX_FUNCTION(uart1),
        UNIPHIER_PINMUX_FUNCTION(uart2),
@@ -1312,43 +1348,36 @@ static const struct uniphier_pinmux_function ph1_pro5_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(xirq),
 };
 
-static struct uniphier_pinctrl_socdata ph1_pro5_pindata = {
-       .groups = ph1_pro5_groups,
-       .groups_count = ARRAY_SIZE(ph1_pro5_groups),
-       .functions = ph1_pro5_functions,
-       .functions_count = ARRAY_SIZE(ph1_pro5_functions),
-       .mux_bits = 4,
-       .reg_stride = 8,
-       .load_pinctrl = true,
-};
-
-static struct pinctrl_desc ph1_pro5_pinctrl_desc = {
-       .name = DRIVER_NAME,
-       .pins = ph1_pro5_pins,
-       .npins = ARRAY_SIZE(ph1_pro5_pins),
-       .owner = THIS_MODULE,
+static struct uniphier_pinctrl_socdata uniphier_pro5_pindata = {
+       .pins = uniphier_pro5_pins,
+       .npins = ARRAY_SIZE(uniphier_pro5_pins),
+       .groups = uniphier_pro5_groups,
+       .groups_count = ARRAY_SIZE(uniphier_pro5_groups),
+       .functions = uniphier_pro5_functions,
+       .functions_count = ARRAY_SIZE(uniphier_pro5_functions),
+       .caps = UNIPHIER_PINCTRL_CAPS_DBGMUX_SEPARATE,
 };
 
-static int ph1_pro5_pinctrl_probe(struct platform_device *pdev)
+static int uniphier_pro5_pinctrl_probe(struct platform_device *pdev)
 {
-       return uniphier_pinctrl_probe(pdev, &ph1_pro5_pinctrl_desc,
-                                     &ph1_pro5_pindata);
+       return uniphier_pinctrl_probe(pdev, &uniphier_pro5_pindata);
 }
 
-static const struct of_device_id ph1_pro5_pinctrl_match[] = {
+static const struct of_device_id uniphier_pro5_pinctrl_match[] = {
+       { .compatible = "socionext,uniphier-pro5-pinctrl" },
        { .compatible = "socionext,ph1-pro5-pinctrl" },
        { /* sentinel */ }
 };
-MODULE_DEVICE_TABLE(of, ph1_pro5_pinctrl_match);
+MODULE_DEVICE_TABLE(of, uniphier_pro5_pinctrl_match);
 
-static struct platform_driver ph1_pro5_pinctrl_driver = {
-       .probe = ph1_pro5_pinctrl_probe,
+static struct platform_driver uniphier_pro5_pinctrl_driver = {
+       .probe = uniphier_pro5_pinctrl_probe,
        .driver = {
-               .name = DRIVER_NAME,
-               .of_match_table = ph1_pro5_pinctrl_match,
+               .name = "uniphier-pro5-pinctrl",
+               .of_match_table = uniphier_pro5_pinctrl_match,
        },
 };
-module_platform_driver(ph1_pro5_pinctrl_driver);
+module_platform_driver(uniphier_pro5_pinctrl_driver);
 
 MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
 MODULE_DESCRIPTION("UniPhier PH1-Pro5 pinctrl driver");
index e868030..85ca5e2 100644 (file)
 
 #include "pinctrl-uniphier.h"
 
-#define DRIVER_NAME "proxstream2-pinctrl"
-
-static const struct pinctrl_pin_desc proxstream2_pins[] = {
+static const struct pinctrl_pin_desc uniphier_pxs2_pins[] = {
        UNIPHIER_PINCTRL_PIN(0, "ED0", UNIPHIER_PIN_IECTRL_NONE,
-                            0, UNIPHIER_PIN_DRV_4_8,
+                            0, UNIPHIER_PIN_DRV_1BIT,
                             0, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(1, "ED1", UNIPHIER_PIN_IECTRL_NONE,
-                            1, UNIPHIER_PIN_DRV_4_8,
+                            1, UNIPHIER_PIN_DRV_1BIT,
                             1, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(2, "ED2", UNIPHIER_PIN_IECTRL_NONE,
-                            2, UNIPHIER_PIN_DRV_4_8,
+                            2, UNIPHIER_PIN_DRV_1BIT,
                             2, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(3, "ED3", UNIPHIER_PIN_IECTRL_NONE,
-                            3, UNIPHIER_PIN_DRV_4_8,
+                            3, UNIPHIER_PIN_DRV_1BIT,
                             3, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(4, "ED4", UNIPHIER_PIN_IECTRL_NONE,
-                            4, UNIPHIER_PIN_DRV_4_8,
+                            4, UNIPHIER_PIN_DRV_1BIT,
                             4, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(5, "ED5", UNIPHIER_PIN_IECTRL_NONE,
-                            5, UNIPHIER_PIN_DRV_4_8,
+                            5, UNIPHIER_PIN_DRV_1BIT,
                             5, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(6, "ED6", UNIPHIER_PIN_IECTRL_NONE,
-                            6, UNIPHIER_PIN_DRV_4_8,
+                            6, UNIPHIER_PIN_DRV_1BIT,
                             6, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(7, "ED7", UNIPHIER_PIN_IECTRL_NONE,
-                            7, UNIPHIER_PIN_DRV_4_8,
+                            7, UNIPHIER_PIN_DRV_1BIT,
                             7, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(8, "XERWE0", UNIPHIER_PIN_IECTRL_NONE,
-                            8, UNIPHIER_PIN_DRV_4_8,
+                            8, UNIPHIER_PIN_DRV_1BIT,
                             8, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(9, "XERWE1", UNIPHIER_PIN_IECTRL_NONE,
-                            9, UNIPHIER_PIN_DRV_4_8,
+                            9, UNIPHIER_PIN_DRV_1BIT,
                             9, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(10, "ERXW", UNIPHIER_PIN_IECTRL_NONE,
-                            10, UNIPHIER_PIN_DRV_4_8,
+                            10, UNIPHIER_PIN_DRV_1BIT,
                             10, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(11, "ES0", UNIPHIER_PIN_IECTRL_NONE,
-                            11, UNIPHIER_PIN_DRV_4_8,
+                            11, UNIPHIER_PIN_DRV_1BIT,
                             11, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(12, "ES1", UNIPHIER_PIN_IECTRL_NONE,
-                            12, UNIPHIER_PIN_DRV_4_8,
+                            12, UNIPHIER_PIN_DRV_1BIT,
                             12, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(13, "ES2", UNIPHIER_PIN_IECTRL_NONE,
-                            13, UNIPHIER_PIN_DRV_4_8,
+                            13, UNIPHIER_PIN_DRV_1BIT,
                             13, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(14, "XECS1", UNIPHIER_PIN_IECTRL_NONE,
-                            14, UNIPHIER_PIN_DRV_4_8,
+                            14, UNIPHIER_PIN_DRV_1BIT,
                             14, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(15, "SMTRST0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             15, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(16, "SMTCMD0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             16, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(17, "SMTD0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             17, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(18, "SMTSEL0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             18, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(19, "SMTCLK0CG", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             19, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(20, "SMTDET0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             20, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(21, "SMTRST1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             21, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(22, "SMTCMD1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             22, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(23, "SMTD1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             23, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(24, "SMTSEL1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             24, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(25, "SMTCLK1CG", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             25, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(26, "SMTDET1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             26, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(27, "XIRQ18", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             27, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(28, "XIRQ19", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             28, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(29, "XIRQ20", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             29, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(30, "XNFRE", UNIPHIER_PIN_IECTRL_NONE,
-                            30, UNIPHIER_PIN_DRV_4_8,
+                            30, UNIPHIER_PIN_DRV_1BIT,
                             30, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(31, "XNFWE", UNIPHIER_PIN_IECTRL_NONE,
-                            31, UNIPHIER_PIN_DRV_4_8,
+                            31, UNIPHIER_PIN_DRV_1BIT,
                             31, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(32, "NFALE", UNIPHIER_PIN_IECTRL_NONE,
-                            32, UNIPHIER_PIN_DRV_4_8,
+                            32, UNIPHIER_PIN_DRV_1BIT,
                             32, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(33, "NFCLE", UNIPHIER_PIN_IECTRL_NONE,
-                            33, UNIPHIER_PIN_DRV_4_8,
+                            33, UNIPHIER_PIN_DRV_1BIT,
                             33, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(34, "XNFWP", UNIPHIER_PIN_IECTRL_NONE,
-                            34, UNIPHIER_PIN_DRV_4_8,
+                            34, UNIPHIER_PIN_DRV_1BIT,
                             34, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(35, "XNFCE0", UNIPHIER_PIN_IECTRL_NONE,
-                            35, UNIPHIER_PIN_DRV_4_8,
+                            35, UNIPHIER_PIN_DRV_1BIT,
                             35, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(36, "NFRYBY0", UNIPHIER_PIN_IECTRL_NONE,
-                            36, UNIPHIER_PIN_DRV_4_8,
+                            36, UNIPHIER_PIN_DRV_1BIT,
                             36, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(37, "XNFCE1", UNIPHIER_PIN_IECTRL_NONE,
-                            37, UNIPHIER_PIN_DRV_4_8,
+                            37, UNIPHIER_PIN_DRV_1BIT,
                             37, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(38, "NFRYBY1", UNIPHIER_PIN_IECTRL_NONE,
-                            38, UNIPHIER_PIN_DRV_4_8,
+                            38, UNIPHIER_PIN_DRV_1BIT,
                             38, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(39, "NFD0", UNIPHIER_PIN_IECTRL_NONE,
-                            39, UNIPHIER_PIN_DRV_4_8,
+                            39, UNIPHIER_PIN_DRV_1BIT,
                             39, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(40, "NFD1", UNIPHIER_PIN_IECTRL_NONE,
-                            40, UNIPHIER_PIN_DRV_4_8,
+                            40, UNIPHIER_PIN_DRV_1BIT,
                             40, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(41, "NFD2", UNIPHIER_PIN_IECTRL_NONE,
-                            41, UNIPHIER_PIN_DRV_4_8,
+                            41, UNIPHIER_PIN_DRV_1BIT,
                             41, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(42, "NFD3", UNIPHIER_PIN_IECTRL_NONE,
-                            42, UNIPHIER_PIN_DRV_4_8,
+                            42, UNIPHIER_PIN_DRV_1BIT,
                             42, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(43, "NFD4", UNIPHIER_PIN_IECTRL_NONE,
-                            43, UNIPHIER_PIN_DRV_4_8,
+                            43, UNIPHIER_PIN_DRV_1BIT,
                             43, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(44, "NFD5", UNIPHIER_PIN_IECTRL_NONE,
-                            44, UNIPHIER_PIN_DRV_4_8,
+                            44, UNIPHIER_PIN_DRV_1BIT,
                             44, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(45, "NFD6", UNIPHIER_PIN_IECTRL_NONE,
-                            45, UNIPHIER_PIN_DRV_4_8,
+                            45, UNIPHIER_PIN_DRV_1BIT,
                             45, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(46, "NFD7", UNIPHIER_PIN_IECTRL_NONE,
-                            46, UNIPHIER_PIN_DRV_4_8,
+                            46, UNIPHIER_PIN_DRV_1BIT,
                             46, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(47, "SDCLK", UNIPHIER_PIN_IECTRL_NONE,
-                            0, UNIPHIER_PIN_DRV_8_12_16_20,
+                            0, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(48, "SDCMD", UNIPHIER_PIN_IECTRL_NONE,
-                            4, UNIPHIER_PIN_DRV_8_12_16_20,
+                            1, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(49, "SDDAT0", UNIPHIER_PIN_IECTRL_NONE,
-                            8, UNIPHIER_PIN_DRV_8_12_16_20,
+                            2, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(50, "SDDAT1", UNIPHIER_PIN_IECTRL_NONE,
-                            12, UNIPHIER_PIN_DRV_8_12_16_20,
+                            3, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(51, "SDDAT2", UNIPHIER_PIN_IECTRL_NONE,
-                            16, UNIPHIER_PIN_DRV_8_12_16_20,
+                            4, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(52, "SDDAT3", UNIPHIER_PIN_IECTRL_NONE,
-                            20, UNIPHIER_PIN_DRV_8_12_16_20,
+                            5, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_UP_FIXED),
        UNIPHIER_PINCTRL_PIN(53, "SDCD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             53, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(54, "SDWP", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             54, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(55, "SDVOLC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             55, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(56, "USB0VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             56, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(57, "USB0OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             57, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(58, "USB1VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             58, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(59, "USB1OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             59, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(60, "USB2VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             60, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(61, "USB2OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             61, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(62, "USB3VBUS", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             62, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(63, "USB3OD", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             63, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(64, "CH0CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             64, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(65, "CH0PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             65, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(66, "CH0VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             66, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(67, "CH0DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             67, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(68, "CH1CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             68, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(69, "CH1PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             69, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(70, "CH1VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             70, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(71, "CH1DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             71, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(72, "XIRQ9", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             72, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(73, "XIRQ10", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             73, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(74, "XIRQ16", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             74, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(75, "CH4CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             75, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(76, "CH4PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             76, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(77, "CH4VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             77, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(78, "CH4DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             78, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(79, "CH5CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             79, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(80, "CH5PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             80, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(81, "CH5VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             81, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(82, "CH5DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             82, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(83, "CH6CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             83, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(84, "CH6PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             84, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(85, "CH6VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             85, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(86, "CH6DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             86, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(87, "STS0CLKO", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             87, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(88, "STS0SYNCO", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             88, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(89, "STS0VALO", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             89, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(90, "STS0DATAO", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             90, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(91, "XIRQ17", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             91, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(92, "PORT163", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             92, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(93, "PORT165", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             93, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(94, "PORT166", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             94, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(95, "PORT132", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             95, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(96, "PORT133", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             96, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(97, "AO2IEC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             97, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(98, "AI2ADCCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             98, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(99, "AI2BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             99, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(100, "AI2LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             100, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(101, "AI2D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             101, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(102, "AI2D1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             102, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(103, "AI2D2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             103, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(104, "AI2D3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             104, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(105, "AO3DACCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             105, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(106, "AO3BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             106, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(107, "AO3LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             107, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(108, "AO3DMIX", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             108, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(109, "SDA0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             109, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(110, "SCL0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             110, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(111, "SDA1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             111, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(112, "SCL1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             112, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(113, "TXD2", 0,
-                            113, UNIPHIER_PIN_DRV_4_8,
+                            113, UNIPHIER_PIN_DRV_1BIT,
                             113, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(114, "RXD2", 0,
-                            114, UNIPHIER_PIN_DRV_4_8,
+                            114, UNIPHIER_PIN_DRV_1BIT,
                             114, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(115, "TXD1", 0,
-                            115, UNIPHIER_PIN_DRV_4_8,
+                            115, UNIPHIER_PIN_DRV_1BIT,
                             115, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(116, "RXD1", 0,
-                            116, UNIPHIER_PIN_DRV_4_8,
+                            116, UNIPHIER_PIN_DRV_1BIT,
                             116, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(117, "PORT190", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             117, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(118, "VI1HSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             118, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(119, "VI1VSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             119, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(120, "VI1DE", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             120, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(121, "XIRQ3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             121, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(122, "XIRQ4", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             122, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(123, "VI1G2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             123, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(124, "VI1G3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             124, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(125, "VI1G4", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             125, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(126, "VI1G5", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             126, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(127, "VI1G6", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             127, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(128, "VI1G7", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             128, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(129, "VI1G8", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             129, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(130, "VI1G9", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             130, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(131, "VI1CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             131, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(132, "PORT05", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             132, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(133, "PORT06", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             133, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(134, "VI1R2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             134, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(135, "VI1R3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             135, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(136, "VI1R4", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             136, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(137, "VI1R5", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             137, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(138, "VI1R6", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             138, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(139, "VI1R7", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             139, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(140, "VI1R8", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             140, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(141, "VI1R9", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             141, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(142, "LPST", UNIPHIER_PIN_IECTRL_NONE,
-                            142, UNIPHIER_PIN_DRV_4_8,
+                            142, UNIPHIER_PIN_DRV_1BIT,
                             142, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(143, "MDC", 0,
-                            143, UNIPHIER_PIN_DRV_4_8,
+                            143, UNIPHIER_PIN_DRV_1BIT,
                             143, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(144, "MDIO", 0,
-                            144, UNIPHIER_PIN_DRV_4_8,
+                            144, UNIPHIER_PIN_DRV_1BIT,
                             144, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(145, "MDIO_INTL", 0,
-                            145, UNIPHIER_PIN_DRV_4_8,
+                            145, UNIPHIER_PIN_DRV_1BIT,
                             145, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(146, "PHYRSTL", 0,
-                            146, UNIPHIER_PIN_DRV_4_8,
+                            146, UNIPHIER_PIN_DRV_1BIT,
                             146, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(147, "RGMII_RXCLK", 0,
-                            147, UNIPHIER_PIN_DRV_4_8,
+                            147, UNIPHIER_PIN_DRV_1BIT,
                             147, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(148, "RGMII_RXD0", 0,
-                            148, UNIPHIER_PIN_DRV_4_8,
+                            148, UNIPHIER_PIN_DRV_1BIT,
                             148, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(149, "RGMII_RXD1", 0,
-                            149, UNIPHIER_PIN_DRV_4_8,
+                            149, UNIPHIER_PIN_DRV_1BIT,
                             149, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(150, "RGMII_RXD2", 0,
-                            150, UNIPHIER_PIN_DRV_4_8,
+                            150, UNIPHIER_PIN_DRV_1BIT,
                             150, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(151, "RGMII_RXD3", 0,
-                            151, UNIPHIER_PIN_DRV_4_8,
+                            151, UNIPHIER_PIN_DRV_1BIT,
                             151, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(152, "RGMII_RXCTL", 0,
-                            152, UNIPHIER_PIN_DRV_4_8,
+                            152, UNIPHIER_PIN_DRV_1BIT,
                             152, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(153, "RGMII_TXCLK", 0,
-                            153, UNIPHIER_PIN_DRV_4_8,
+                            153, UNIPHIER_PIN_DRV_1BIT,
                             153, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(154, "RGMII_TXD0", 0,
-                            154, UNIPHIER_PIN_DRV_4_8,
+                            154, UNIPHIER_PIN_DRV_1BIT,
                             154, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(155, "RGMII_TXD1", 0,
-                            155, UNIPHIER_PIN_DRV_4_8,
+                            155, UNIPHIER_PIN_DRV_1BIT,
                             155, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(156, "RGMII_TXD2", 0,
-                            156, UNIPHIER_PIN_DRV_4_8,
+                            156, UNIPHIER_PIN_DRV_1BIT,
                             156, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(157, "RGMII_TXD3", 0,
-                            157, UNIPHIER_PIN_DRV_4_8,
+                            157, UNIPHIER_PIN_DRV_1BIT,
                             157, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(158, "RGMII_TXCTL", 0,
-                            158, UNIPHIER_PIN_DRV_4_8,
+                            158, UNIPHIER_PIN_DRV_1BIT,
                             158, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(159, "SDA3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             159, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(160, "SCL3", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             160, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(161, "AI1ADCCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             161, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(162, "AI1BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             162, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(163, "CH2CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             163, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(164, "CH2PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             164, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(165, "CH2VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             165, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(166, "CH2DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             166, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(167, "CH3CLK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             167, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(168, "CH3PSYNC", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             168, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(169, "CH3VAL", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             169, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(170, "CH3DATA", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             170, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(171, "SDA2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             171, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(172, "SCL2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             172, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(173, "AI1LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             173, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(174, "AI1D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             174, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(175, "AO2LRCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             175, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(176, "AO2D0", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             176, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(177, "AO2DACCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             177, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(178, "AO2BCK", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             178, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(179, "PORT222", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             179, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(180, "PORT223", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             180, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(181, "PORT224", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             181, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(182, "PORT225", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             182, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(183, "PORT226", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             183, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(184, "PORT227", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             184, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(185, "PORT230", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             185, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(186, "FANPWM", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             186, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(187, "HRDDCSDA0", 0,
-                            187, UNIPHIER_PIN_DRV_4_8,
+                            187, UNIPHIER_PIN_DRV_1BIT,
                             187, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(188, "HRDDCSCL0", 0,
-                            188, UNIPHIER_PIN_DRV_4_8,
+                            188, UNIPHIER_PIN_DRV_1BIT,
                             188, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(189, "HRDDCSDA1", 0,
-                            189, UNIPHIER_PIN_DRV_4_8,
+                            189, UNIPHIER_PIN_DRV_1BIT,
                             189, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(190, "HRDDCSCL1", 0,
-                            190, UNIPHIER_PIN_DRV_4_8,
+                            190, UNIPHIER_PIN_DRV_1BIT,
                             190, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(191, "HTDDCSDA0", 0,
-                            191, UNIPHIER_PIN_DRV_4_8,
+                            191, UNIPHIER_PIN_DRV_1BIT,
                             191, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(192, "HTDDCSCL0", 0,
-                            192, UNIPHIER_PIN_DRV_4_8,
+                            192, UNIPHIER_PIN_DRV_1BIT,
                             192, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(193, "HTDDCSDA1", 0,
-                            193, UNIPHIER_PIN_DRV_4_8,
+                            193, UNIPHIER_PIN_DRV_1BIT,
                             193, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(194, "HTDDCSCL1", 0,
-                            194, UNIPHIER_PIN_DRV_4_8,
+                            194, UNIPHIER_PIN_DRV_1BIT,
                             194, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(195, "PORT241", 0,
-                            195, UNIPHIER_PIN_DRV_4_8,
+                            195, UNIPHIER_PIN_DRV_1BIT,
                             195, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(196, "PORT242", 0,
-                            196, UNIPHIER_PIN_DRV_4_8,
+                            196, UNIPHIER_PIN_DRV_1BIT,
                             196, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(197, "PORT243", 0,
-                            197, UNIPHIER_PIN_DRV_4_8,
+                            197, UNIPHIER_PIN_DRV_1BIT,
                             197, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(198, "MVSYNC", 0,
-                            198, UNIPHIER_PIN_DRV_4_8,
+                            198, UNIPHIER_PIN_DRV_1BIT,
                             198, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(199, "SPISYNC0", UNIPHIER_PIN_IECTRL_NONE,
-                            199, UNIPHIER_PIN_DRV_4_8,
+                            199, UNIPHIER_PIN_DRV_1BIT,
                             199, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(200, "SPISCLK0", UNIPHIER_PIN_IECTRL_NONE,
-                            200, UNIPHIER_PIN_DRV_4_8,
+                            200, UNIPHIER_PIN_DRV_1BIT,
                             200, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(201, "SPITXD0", UNIPHIER_PIN_IECTRL_NONE,
-                            201, UNIPHIER_PIN_DRV_4_8,
+                            201, UNIPHIER_PIN_DRV_1BIT,
                             201, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(202, "SPIRXD0", UNIPHIER_PIN_IECTRL_NONE,
-                            202, UNIPHIER_PIN_DRV_4_8,
+                            202, UNIPHIER_PIN_DRV_1BIT,
                             202, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(203, "CK54EXI", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             203, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(204, "AEXCKA1", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             204, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(205, "AEXCKA2", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             205, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(206, "CK27EXI", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_8,
+                            -1, UNIPHIER_PIN_DRV_FIXED8,
                             206, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(207, "STCDIN", 0,
-                            207, UNIPHIER_PIN_DRV_4_8,
+                            207, UNIPHIER_PIN_DRV_1BIT,
                             207, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(208, "PHSYNI", 0,
-                            208, UNIPHIER_PIN_DRV_4_8,
+                            208, UNIPHIER_PIN_DRV_1BIT,
                             208, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(209, "PVSYNI", 0,
-                            209, UNIPHIER_PIN_DRV_4_8,
+                            209, UNIPHIER_PIN_DRV_1BIT,
                             209, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(210, "MVSYN", UNIPHIER_PIN_IECTRL_NONE,
-                            210, UNIPHIER_PIN_DRV_4_8,
+                            210, UNIPHIER_PIN_DRV_1BIT,
                             210, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(211, "STCV", UNIPHIER_PIN_IECTRL_NONE,
-                            211, UNIPHIER_PIN_DRV_4_8,
+                            211, UNIPHIER_PIN_DRV_1BIT,
                             211, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(212, "PORT262", UNIPHIER_PIN_IECTRL_NONE,
-                            212, UNIPHIER_PIN_DRV_4_8,
+                            212, UNIPHIER_PIN_DRV_1BIT,
                             212, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(213, "USB0VBUS_IRQ", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             213, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(214, "USB1VBUS_IRQ", UNIPHIER_PIN_IECTRL_NONE,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             214, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(215, "PORT265", UNIPHIER_PIN_IECTRL_NONE,
-                            215, UNIPHIER_PIN_DRV_4_8,
+                            215, UNIPHIER_PIN_DRV_1BIT,
                             215, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(216, "CK25O", 0,
-                            216, UNIPHIER_PIN_DRV_4_8,
+                            216, UNIPHIER_PIN_DRV_1BIT,
                             216, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(217, "TXD0", 0,
-                            217, UNIPHIER_PIN_DRV_4_8,
+                            217, UNIPHIER_PIN_DRV_1BIT,
                             217, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(218, "RXD0", 0,
-                            218, UNIPHIER_PIN_DRV_4_8,
+                            218, UNIPHIER_PIN_DRV_1BIT,
                             218, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(219, "TXD3", 0,
-                            219, UNIPHIER_PIN_DRV_4_8,
+                            219, UNIPHIER_PIN_DRV_1BIT,
                             219, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(220, "RXD3", 0,
-                            220, UNIPHIER_PIN_DRV_4_8,
+                            220, UNIPHIER_PIN_DRV_1BIT,
                             220, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(221, "PORT273", 0,
-                            221, UNIPHIER_PIN_DRV_4_8,
+                            221, UNIPHIER_PIN_DRV_1BIT,
                             221, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(222, "STCDOUTC", 0,
-                            222, UNIPHIER_PIN_DRV_4_8,
+                            222, UNIPHIER_PIN_DRV_1BIT,
                             222, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(223, "PORT274", 0,
-                            223, UNIPHIER_PIN_DRV_4_8,
+                            223, UNIPHIER_PIN_DRV_1BIT,
                             223, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(224, "PORT275", 0,
-                            224, UNIPHIER_PIN_DRV_4_8,
+                            224, UNIPHIER_PIN_DRV_1BIT,
                             224, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(225, "PORT276", 0,
-                            225, UNIPHIER_PIN_DRV_4_8,
+                            225, UNIPHIER_PIN_DRV_1BIT,
                             225, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(226, "PORT277", 0,
-                            226, UNIPHIER_PIN_DRV_4_8,
+                            226, UNIPHIER_PIN_DRV_1BIT,
                             226, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(227, "PORT280", 0,
-                            227, UNIPHIER_PIN_DRV_4_8,
+                            227, UNIPHIER_PIN_DRV_1BIT,
                             227, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(228, "PORT281", 0,
-                            228, UNIPHIER_PIN_DRV_4_8,
+                            228, UNIPHIER_PIN_DRV_1BIT,
                             228, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(229, "PORT282", 0,
-                            229, UNIPHIER_PIN_DRV_4_8,
+                            229, UNIPHIER_PIN_DRV_1BIT,
                             229, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(230, "PORT283", 0,
-                            230, UNIPHIER_PIN_DRV_4_8,
+                            230, UNIPHIER_PIN_DRV_1BIT,
                             230, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(231, "PORT284", 0,
-                            231, UNIPHIER_PIN_DRV_4_8,
+                            231, UNIPHIER_PIN_DRV_1BIT,
                             231, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(232, "PORT285", 0,
-                            232, UNIPHIER_PIN_DRV_4_8,
+                            232, UNIPHIER_PIN_DRV_1BIT,
                             232, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(233, "T0HPD", 0,
-                            233, UNIPHIER_PIN_DRV_4_8,
+                            233, UNIPHIER_PIN_DRV_1BIT,
                             233, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(234, "T1HPD", 0,
-                            234, UNIPHIER_PIN_DRV_4_8,
+                            234, UNIPHIER_PIN_DRV_1BIT,
                             234, UNIPHIER_PIN_PULL_DOWN),
 };
 
 static const unsigned emmc_pins[] = {36, 37, 38, 39, 40, 41, 42};
-static const unsigned emmc_muxvals[] = {9, 9, 9, 9, 9, 9, 9};
+static const int emmc_muxvals[] = {9, 9, 9, 9, 9, 9, 9};
 static const unsigned emmc_dat8_pins[] = {43, 44, 45, 46};
-static const unsigned emmc_dat8_muxvals[] = {9, 9, 9, 9};
+static const int emmc_dat8_muxvals[] = {9, 9, 9, 9};
+static const unsigned ether_mii_pins[] = {143, 144, 145, 146, 147, 148, 149,
+                                         150, 151, 152, 153, 154, 155, 156,
+                                         158, 159, 199, 200, 201, 202};
+static const int ether_mii_muxvals[] = {8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10,
+                                       10, 10, 10, 10, 10, 12, 12, 12, 12};
+static const unsigned ether_rgmii_pins[] = {143, 144, 145, 146, 147, 148, 149,
+                                           150, 151, 152, 153, 154, 155, 156,
+                                           157, 158};
+static const int ether_rgmii_muxvals[] = {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+                                         8, 8, 8, 8};
+static const unsigned ether_rmii_pins[] = {143, 144, 145, 146, 147, 148, 149,
+                                          150, 152, 154, 155, 158};
+static const int ether_rmii_muxvals[] = {8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9};
 static const unsigned i2c0_pins[] = {109, 110};
-static const unsigned i2c0_muxvals[] = {8, 8};
+static const int i2c0_muxvals[] = {8, 8};
 static const unsigned i2c1_pins[] = {111, 112};
-static const unsigned i2c1_muxvals[] = {8, 8};
+static const int i2c1_muxvals[] = {8, 8};
 static const unsigned i2c2_pins[] = {171, 172};
-static const unsigned i2c2_muxvals[] = {8, 8};
+static const int i2c2_muxvals[] = {8, 8};
 static const unsigned i2c3_pins[] = {159, 160};
-static const unsigned i2c3_muxvals[] = {8, 8};
+static const int i2c3_muxvals[] = {8, 8};
 static const unsigned i2c5_pins[] = {183, 184};
-static const unsigned i2c5_muxvals[] = {11, 11};
+static const int i2c5_muxvals[] = {11, 11};
 static const unsigned i2c6_pins[] = {185, 186};
-static const unsigned i2c6_muxvals[] = {11, 11};
+static const int i2c6_muxvals[] = {11, 11};
 static const unsigned nand_pins[] = {30, 31, 32, 33, 34, 35, 36, 39, 40, 41,
                                     42, 43, 44, 45, 46};
-static const unsigned nand_muxvals[] = {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-                                       8, 8};
+static const int nand_muxvals[] = {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8};
 static const unsigned nand_cs1_pins[] = {37, 38};
-static const unsigned nand_cs1_muxvals[] = {8, 8};
+static const int nand_cs1_muxvals[] = {8, 8};
 static const unsigned sd_pins[] = {47, 48, 49, 50, 51, 52, 53, 54, 55};
-static const unsigned sd_muxvals[] = {8, 8, 8, 8, 8, 8, 8, 8, 8};
+static const int sd_muxvals[] = {8, 8, 8, 8, 8, 8, 8, 8, 8};
+static const unsigned system_bus_pins[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+                                          11, 12, 13};
+static const int system_bus_muxvals[] = {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+                                        8};
+static const unsigned system_bus_cs1_pins[] = {14};
+static const int system_bus_cs1_muxvals[] = {8};
 static const unsigned uart0_pins[] = {217, 218};
-static const unsigned uart0_muxvals[] = {8, 8};
+static const int uart0_muxvals[] = {8, 8};
 static const unsigned uart0b_pins[] = {179, 180};
-static const unsigned uart0b_muxvals[] = {10, 10};
+static const int uart0b_muxvals[] = {10, 10};
 static const unsigned uart1_pins[] = {115, 116};
-static const unsigned uart1_muxvals[] = {8, 8};
+static const int uart1_muxvals[] = {8, 8};
 static const unsigned uart2_pins[] = {113, 114};
-static const unsigned uart2_muxvals[] = {8, 8};
+static const int uart2_muxvals[] = {8, 8};
 static const unsigned uart3_pins[] = {219, 220};
-static const unsigned uart3_muxvals[] = {8, 8};
+static const int uart3_muxvals[] = {8, 8};
 static const unsigned uart3b_pins[] = {181, 182};
-static const unsigned uart3b_muxvals[] = {10, 10};
+static const int uart3b_muxvals[] = {10, 10};
 static const unsigned usb0_pins[] = {56, 57};
-static const unsigned usb0_muxvals[] = {8, 8};
+static const int usb0_muxvals[] = {8, 8};
 static const unsigned usb1_pins[] = {58, 59};
-static const unsigned usb1_muxvals[] = {8, 8};
+static const int usb1_muxvals[] = {8, 8};
 static const unsigned usb2_pins[] = {60, 61};
-static const unsigned usb2_muxvals[] = {8, 8};
+static const int usb2_muxvals[] = {8, 8};
 static const unsigned usb3_pins[] = {62, 63};
-static const unsigned usb3_muxvals[] = {8, 8};
+static const int usb3_muxvals[] = {8, 8};
 static const unsigned port_range0_pins[] = {
        127, 128, 129, 130, 131, 132, 133, 134,         /* PORT0x */
        135, 136, 137, 138, 139, 140, 141, 142,         /* PORT1x */
@@ -786,7 +802,7 @@ static const unsigned port_range0_pins[] = {
        61, 62, 63, 64, 65, 66, 67, 68,                 /* PORT9x */
        69, 70, 71, 76, 77, 78, 79, 80,                 /* PORT10x */
 };
-static const unsigned port_range0_muxvals[] = {
+static const int port_range0_muxvals[] = {
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT0x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT1x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT2x */
@@ -818,7 +834,7 @@ static const unsigned port_range1_pins[] = {
        218, 219, 220, 221, 223, 224, 225, 226,         /* PORT27x */
        227, 228, 229, 230, 231, 232, 233, 234,         /* PORT28x */
 };
-static const unsigned port_range1_muxvals[] = {
+static const int port_range1_muxvals[] = {
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT12x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT13x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT14x */
@@ -842,15 +858,18 @@ static const unsigned xirq_pins[] = {
        126, 72, 73, 92, 177, 93, 94, 176,              /* XIRQ8-15 */
        74, 91, 27, 28, 29, 75, 20, 26,                 /* XIRQ16-23 */
 };
-static const unsigned xirq_muxvals[] = {
+static const int xirq_muxvals[] = {
        14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ0-7 */
        14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ8-15 */
        14, 14, 14, 14, 14, 14, 14, 14,                 /* XIRQ16-23 */
 };
 
-static const struct uniphier_pinctrl_group proxstream2_groups[] = {
+static const struct uniphier_pinctrl_group uniphier_pxs2_groups[] = {
        UNIPHIER_PINCTRL_GROUP(emmc),
        UNIPHIER_PINCTRL_GROUP(emmc_dat8),
+       UNIPHIER_PINCTRL_GROUP(ether_mii),
+       UNIPHIER_PINCTRL_GROUP(ether_rgmii),
+       UNIPHIER_PINCTRL_GROUP(ether_rmii),
        UNIPHIER_PINCTRL_GROUP(i2c0),
        UNIPHIER_PINCTRL_GROUP(i2c1),
        UNIPHIER_PINCTRL_GROUP(i2c2),
@@ -860,6 +879,8 @@ static const struct uniphier_pinctrl_group proxstream2_groups[] = {
        UNIPHIER_PINCTRL_GROUP(nand),
        UNIPHIER_PINCTRL_GROUP(nand_cs1),
        UNIPHIER_PINCTRL_GROUP(sd),
+       UNIPHIER_PINCTRL_GROUP(system_bus),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs1),
        UNIPHIER_PINCTRL_GROUP(uart0),
        UNIPHIER_PINCTRL_GROUP(uart0b),
        UNIPHIER_PINCTRL_GROUP(uart1),
@@ -1124,6 +1145,9 @@ static const struct uniphier_pinctrl_group proxstream2_groups[] = {
 };
 
 static const char * const emmc_groups[] = {"emmc", "emmc_dat8"};
+static const char * const ether_mii_groups[] = {"ether_mii"};
+static const char * const ether_rgmii_groups[] = {"ether_rgmii"};
+static const char * const ether_rmii_groups[] = {"ether_rmii"};
 static const char * const i2c0_groups[] = {"i2c0"};
 static const char * const i2c1_groups[] = {"i2c1"};
 static const char * const i2c2_groups[] = {"i2c2"};
@@ -1132,6 +1156,8 @@ static const char * const i2c5_groups[] = {"i2c5"};
 static const char * const i2c6_groups[] = {"i2c6"};
 static const char * const nand_groups[] = {"nand", "nand_cs1"};
 static const char * const sd_groups[] = {"sd"};
+static const char * const system_bus_groups[] = {"system_bus",
+                                                "system_bus_cs1"};
 static const char * const uart0_groups[] = {"uart0", "uart0b"};
 static const char * const uart1_groups[] = {"uart1"};
 static const char * const uart2_groups[] = {"uart2"};
@@ -1208,8 +1234,11 @@ static const char * const xirq_groups[] = {
        "xirq20", "xirq21", "xirq22", "xirq23",
 };
 
-static const struct uniphier_pinmux_function proxstream2_functions[] = {
+static const struct uniphier_pinmux_function uniphier_pxs2_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(emmc),
+       UNIPHIER_PINMUX_FUNCTION(ether_mii),
+       UNIPHIER_PINMUX_FUNCTION(ether_rgmii),
+       UNIPHIER_PINMUX_FUNCTION(ether_rmii),
        UNIPHIER_PINMUX_FUNCTION(i2c0),
        UNIPHIER_PINMUX_FUNCTION(i2c1),
        UNIPHIER_PINMUX_FUNCTION(i2c2),
@@ -1218,6 +1247,7 @@ static const struct uniphier_pinmux_function proxstream2_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(i2c6),
        UNIPHIER_PINMUX_FUNCTION(nand),
        UNIPHIER_PINMUX_FUNCTION(sd),
+       UNIPHIER_PINMUX_FUNCTION(system_bus),
        UNIPHIER_PINMUX_FUNCTION(uart0),
        UNIPHIER_PINMUX_FUNCTION(uart1),
        UNIPHIER_PINMUX_FUNCTION(uart2),
@@ -1230,43 +1260,36 @@ static const struct uniphier_pinmux_function proxstream2_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(xirq),
 };
 
-static struct uniphier_pinctrl_socdata proxstream2_pindata = {
-       .groups = proxstream2_groups,
-       .groups_count = ARRAY_SIZE(proxstream2_groups),
-       .functions = proxstream2_functions,
-       .functions_count = ARRAY_SIZE(proxstream2_functions),
-       .mux_bits = 8,
-       .reg_stride = 4,
-       .load_pinctrl = false,
-};
-
-static struct pinctrl_desc proxstream2_pinctrl_desc = {
-       .name = DRIVER_NAME,
-       .pins = proxstream2_pins,
-       .npins = ARRAY_SIZE(proxstream2_pins),
-       .owner = THIS_MODULE,
+static struct uniphier_pinctrl_socdata uniphier_pxs2_pindata = {
+       .pins = uniphier_pxs2_pins,
+       .npins = ARRAY_SIZE(uniphier_pxs2_pins),
+       .groups = uniphier_pxs2_groups,
+       .groups_count = ARRAY_SIZE(uniphier_pxs2_groups),
+       .functions = uniphier_pxs2_functions,
+       .functions_count = ARRAY_SIZE(uniphier_pxs2_functions),
+       .caps = 0,
 };
 
-static int proxstream2_pinctrl_probe(struct platform_device *pdev)
+static int uniphier_pxs2_pinctrl_probe(struct platform_device *pdev)
 {
-       return uniphier_pinctrl_probe(pdev, &proxstream2_pinctrl_desc,
-                                     &proxstream2_pindata);
+       return uniphier_pinctrl_probe(pdev, &uniphier_pxs2_pindata);
 }
 
-static const struct of_device_id proxstream2_pinctrl_match[] = {
+static const struct of_device_id uniphier_pxs2_pinctrl_match[] = {
+       { .compatible = "socionext,uniphier-pxs2-pinctrl" },
        { .compatible = "socionext,proxstream2-pinctrl" },
        { /* sentinel */ }
 };
-MODULE_DEVICE_TABLE(of, proxstream2_pinctrl_match);
+MODULE_DEVICE_TABLE(of, uniphier_pxs2_pinctrl_match);
 
-static struct platform_driver proxstream2_pinctrl_driver = {
-       .probe = proxstream2_pinctrl_probe,
+static struct platform_driver uniphier_pxs2_pinctrl_driver = {
+       .probe = uniphier_pxs2_pinctrl_probe,
        .driver = {
-               .name = DRIVER_NAME,
-               .of_match_table = proxstream2_pinctrl_match,
+               .name = "uniphier-pxs2-pinctrl",
+               .of_match_table = uniphier_pxs2_pinctrl_match,
        },
 };
-module_platform_driver(proxstream2_pinctrl_driver);
+module_platform_driver(uniphier_pxs2_pinctrl_driver);
 
 MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
 MODULE_DESCRIPTION("UniPhier ProXstream2 pinctrl driver");
index ceb7a98..da689d8 100644 (file)
 
 #include "pinctrl-uniphier.h"
 
-#define DRIVER_NAME "ph1-sld8-pinctrl"
-
-static const struct pinctrl_pin_desc ph1_sld8_pins[] = {
+static const struct pinctrl_pin_desc uniphier_sld8_pins[] = {
        UNIPHIER_PINCTRL_PIN(0, "PCA00", 0,
-                            15, UNIPHIER_PIN_DRV_4_8,
+                            15, UNIPHIER_PIN_DRV_1BIT,
                             15, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(1, "PCA01", 0,
-                            16, UNIPHIER_PIN_DRV_4_8,
+                            16, UNIPHIER_PIN_DRV_1BIT,
                             16, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(2, "PCA02", 0,
-                            17, UNIPHIER_PIN_DRV_4_8,
+                            17, UNIPHIER_PIN_DRV_1BIT,
                             17, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(3, "PCA03", 0,
-                            18, UNIPHIER_PIN_DRV_4_8,
+                            18, UNIPHIER_PIN_DRV_1BIT,
                             18, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(4, "PCA04", 0,
-                            19, UNIPHIER_PIN_DRV_4_8,
+                            19, UNIPHIER_PIN_DRV_1BIT,
                             19, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(5, "PCA05", 0,
-                            20, UNIPHIER_PIN_DRV_4_8,
+                            20, UNIPHIER_PIN_DRV_1BIT,
                             20, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(6, "PCA06", 0,
-                            21, UNIPHIER_PIN_DRV_4_8,
+                            21, UNIPHIER_PIN_DRV_1BIT,
                             21, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(7, "PCA07", 0,
-                            22, UNIPHIER_PIN_DRV_4_8,
+                            22, UNIPHIER_PIN_DRV_1BIT,
                             22, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(8, "PCA08", 0,
-                            23, UNIPHIER_PIN_DRV_4_8,
+                            23, UNIPHIER_PIN_DRV_1BIT,
                             23, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(9, "PCA09", 0,
-                            24, UNIPHIER_PIN_DRV_4_8,
+                            24, UNIPHIER_PIN_DRV_1BIT,
                             24, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(10, "PCA10", 0,
-                            25, UNIPHIER_PIN_DRV_4_8,
+                            25, UNIPHIER_PIN_DRV_1BIT,
                             25, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(11, "PCA11", 0,
-                            26, UNIPHIER_PIN_DRV_4_8,
+                            26, UNIPHIER_PIN_DRV_1BIT,
                             26, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(12, "PCA12", 0,
-                            27, UNIPHIER_PIN_DRV_4_8,
+                            27, UNIPHIER_PIN_DRV_1BIT,
                             27, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(13, "PCA13", 0,
-                            28, UNIPHIER_PIN_DRV_4_8,
+                            28, UNIPHIER_PIN_DRV_1BIT,
                             28, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(14, "PCA14", 0,
-                            29, UNIPHIER_PIN_DRV_4_8,
+                            29, UNIPHIER_PIN_DRV_1BIT,
                             29, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(15, "XNFRE_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            30, UNIPHIER_PIN_DRV_4_8,
+                            30, UNIPHIER_PIN_DRV_1BIT,
                             30, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(16, "XNFWE_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            31, UNIPHIER_PIN_DRV_4_8,
+                            31, UNIPHIER_PIN_DRV_1BIT,
                             31, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(17, "NFALE_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            32, UNIPHIER_PIN_DRV_4_8,
+                            32, UNIPHIER_PIN_DRV_1BIT,
                             32, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(18, "NFCLE_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            33, UNIPHIER_PIN_DRV_4_8,
+                            33, UNIPHIER_PIN_DRV_1BIT,
                             33, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(19, "XNFWP_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            34, UNIPHIER_PIN_DRV_4_8,
+                            34, UNIPHIER_PIN_DRV_1BIT,
                             34, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(20, "XNFCE0_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            35, UNIPHIER_PIN_DRV_4_8,
+                            35, UNIPHIER_PIN_DRV_1BIT,
                             35, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(21, "NANDRYBY0_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            36, UNIPHIER_PIN_DRV_4_8,
+                            36, UNIPHIER_PIN_DRV_1BIT,
                             36, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(22, "XNFCE1_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            0, UNIPHIER_PIN_DRV_8_12_16_20,
+                            0, UNIPHIER_PIN_DRV_2BIT,
                             119, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(23, "NANDRYBY1_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            4, UNIPHIER_PIN_DRV_8_12_16_20,
+                            1, UNIPHIER_PIN_DRV_2BIT,
                             120, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(24, "NFD0_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            8, UNIPHIER_PIN_DRV_8_12_16_20,
+                            2, UNIPHIER_PIN_DRV_2BIT,
                             121, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(25, "NFD1_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            12, UNIPHIER_PIN_DRV_8_12_16_20,
+                            3, UNIPHIER_PIN_DRV_2BIT,
                             122, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(26, "NFD2_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            16, UNIPHIER_PIN_DRV_8_12_16_20,
+                            4, UNIPHIER_PIN_DRV_2BIT,
                             123, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(27, "NFD3_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            20, UNIPHIER_PIN_DRV_8_12_16_20,
+                            5, UNIPHIER_PIN_DRV_2BIT,
                             124, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(28, "NFD4_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            24, UNIPHIER_PIN_DRV_8_12_16_20,
+                            6, UNIPHIER_PIN_DRV_2BIT,
                             125, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(29, "NFD5_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            28, UNIPHIER_PIN_DRV_8_12_16_20,
+                            7, UNIPHIER_PIN_DRV_2BIT,
                             126, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(30, "NFD6_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            32, UNIPHIER_PIN_DRV_8_12_16_20,
+                            8, UNIPHIER_PIN_DRV_2BIT,
                             127, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(31, "NFD7_GB", UNIPHIER_PIN_IECTRL_NONE,
-                            36, UNIPHIER_PIN_DRV_8_12_16_20,
+                            9, UNIPHIER_PIN_DRV_2BIT,
                             128, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(32, "SDCLK", 8,
-                            40, UNIPHIER_PIN_DRV_8_12_16_20,
+                            10, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(33, "SDCMD", 8,
-                            44, UNIPHIER_PIN_DRV_8_12_16_20,
+                            11, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(34, "SDDAT0", 8,
-                            48, UNIPHIER_PIN_DRV_8_12_16_20,
+                            12, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(35, "SDDAT1", 8,
-                            52, UNIPHIER_PIN_DRV_8_12_16_20,
+                            13, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(36, "SDDAT2", 8,
-                            56, UNIPHIER_PIN_DRV_8_12_16_20,
+                            14, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(37, "SDDAT3", 8,
-                            60, UNIPHIER_PIN_DRV_8_12_16_20,
+                            15, UNIPHIER_PIN_DRV_2BIT,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(38, "SDCD", 8,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             129, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(39, "SDWP", 8,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             130, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(40, "SDVOLC", 9,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             131, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(41, "USB0VBUS", 0,
-                            37, UNIPHIER_PIN_DRV_4_8,
+                            37, UNIPHIER_PIN_DRV_1BIT,
                             37, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(42, "USB0OD", 0,
-                            38, UNIPHIER_PIN_DRV_4_8,
+                            38, UNIPHIER_PIN_DRV_1BIT,
                             38, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(43, "USB1VBUS", 0,
-                            39, UNIPHIER_PIN_DRV_4_8,
+                            39, UNIPHIER_PIN_DRV_1BIT,
                             39, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(44, "USB1OD", 0,
-                            40, UNIPHIER_PIN_DRV_4_8,
+                            40, UNIPHIER_PIN_DRV_1BIT,
                             40, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(45, "PCRESET", 0,
-                            41, UNIPHIER_PIN_DRV_4_8,
+                            41, UNIPHIER_PIN_DRV_1BIT,
                             41, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(46, "PCREG", 0,
-                            42, UNIPHIER_PIN_DRV_4_8,
+                            42, UNIPHIER_PIN_DRV_1BIT,
                             42, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(47, "PCCE2", 0,
-                            43, UNIPHIER_PIN_DRV_4_8,
+                            43, UNIPHIER_PIN_DRV_1BIT,
                             43, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(48, "PCVS1", 0,
-                            44, UNIPHIER_PIN_DRV_4_8,
+                            44, UNIPHIER_PIN_DRV_1BIT,
                             44, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(49, "PCCD2", 0,
-                            45, UNIPHIER_PIN_DRV_4_8,
+                            45, UNIPHIER_PIN_DRV_1BIT,
                             45, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(50, "PCCD1", 0,
-                            46, UNIPHIER_PIN_DRV_4_8,
+                            46, UNIPHIER_PIN_DRV_1BIT,
                             46, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(51, "PCREADY", 0,
-                            47, UNIPHIER_PIN_DRV_4_8,
+                            47, UNIPHIER_PIN_DRV_1BIT,
                             47, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(52, "PCDOE", 0,
-                            48, UNIPHIER_PIN_DRV_4_8,
+                            48, UNIPHIER_PIN_DRV_1BIT,
                             48, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(53, "PCCE1", 0,
-                            49, UNIPHIER_PIN_DRV_4_8,
+                            49, UNIPHIER_PIN_DRV_1BIT,
                             49, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(54, "PCWE", 0,
-                            50, UNIPHIER_PIN_DRV_4_8,
+                            50, UNIPHIER_PIN_DRV_1BIT,
                             50, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(55, "PCOE", 0,
-                            51, UNIPHIER_PIN_DRV_4_8,
+                            51, UNIPHIER_PIN_DRV_1BIT,
                             51, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(56, "PCWAIT", 0,
-                            52, UNIPHIER_PIN_DRV_4_8,
+                            52, UNIPHIER_PIN_DRV_1BIT,
                             52, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(57, "PCIOWR", 0,
-                            53, UNIPHIER_PIN_DRV_4_8,
+                            53, UNIPHIER_PIN_DRV_1BIT,
                             53, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(58, "PCIORD", 0,
-                            54, UNIPHIER_PIN_DRV_4_8,
+                            54, UNIPHIER_PIN_DRV_1BIT,
                             54, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(59, "HS0DIN0", 0,
-                            55, UNIPHIER_PIN_DRV_4_8,
+                            55, UNIPHIER_PIN_DRV_1BIT,
                             55, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(60, "HS0DIN1", 0,
-                            56, UNIPHIER_PIN_DRV_4_8,
+                            56, UNIPHIER_PIN_DRV_1BIT,
                             56, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(61, "HS0DIN2", 0,
-                            57, UNIPHIER_PIN_DRV_4_8,
+                            57, UNIPHIER_PIN_DRV_1BIT,
                             57, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(62, "HS0DIN3", 0,
-                            58, UNIPHIER_PIN_DRV_4_8,
+                            58, UNIPHIER_PIN_DRV_1BIT,
                             58, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(63, "HS0DIN4", 0,
-                            59, UNIPHIER_PIN_DRV_4_8,
+                            59, UNIPHIER_PIN_DRV_1BIT,
                             59, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(64, "HS0DIN5", 0,
-                            60, UNIPHIER_PIN_DRV_4_8,
+                            60, UNIPHIER_PIN_DRV_1BIT,
                             60, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(65, "HS0DIN6", 0,
-                            61, UNIPHIER_PIN_DRV_4_8,
+                            61, UNIPHIER_PIN_DRV_1BIT,
                             61, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(66, "HS0DIN7", 0,
-                            62, UNIPHIER_PIN_DRV_4_8,
+                            62, UNIPHIER_PIN_DRV_1BIT,
                             62, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(67, "HS0BCLKIN", 0,
-                            63, UNIPHIER_PIN_DRV_4_8,
+                            63, UNIPHIER_PIN_DRV_1BIT,
                             63, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(68, "HS0VALIN", 0,
-                            64, UNIPHIER_PIN_DRV_4_8,
+                            64, UNIPHIER_PIN_DRV_1BIT,
                             64, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(69, "HS0SYNCIN", 0,
-                            65, UNIPHIER_PIN_DRV_4_8,
+                            65, UNIPHIER_PIN_DRV_1BIT,
                             65, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(70, "HSDOUT0", 0,
-                            66, UNIPHIER_PIN_DRV_4_8,
+                            66, UNIPHIER_PIN_DRV_1BIT,
                             66, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(71, "HSDOUT1", 0,
-                            67, UNIPHIER_PIN_DRV_4_8,
+                            67, UNIPHIER_PIN_DRV_1BIT,
                             67, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(72, "HSDOUT2", 0,
-                            68, UNIPHIER_PIN_DRV_4_8,
+                            68, UNIPHIER_PIN_DRV_1BIT,
                             68, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(73, "HSDOUT3", 0,
-                            69, UNIPHIER_PIN_DRV_4_8,
+                            69, UNIPHIER_PIN_DRV_1BIT,
                             69, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(74, "HSDOUT4", 0,
-                            70, UNIPHIER_PIN_DRV_4_8,
+                            70, UNIPHIER_PIN_DRV_1BIT,
                             70, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(75, "HSDOUT5", 0,
-                            71, UNIPHIER_PIN_DRV_4_8,
+                            71, UNIPHIER_PIN_DRV_1BIT,
                             71, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(76, "HSDOUT6", 0,
-                            72, UNIPHIER_PIN_DRV_4_8,
+                            72, UNIPHIER_PIN_DRV_1BIT,
                             72, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(77, "HSDOUT7", 0,
-                            73, UNIPHIER_PIN_DRV_4_8,
+                            73, UNIPHIER_PIN_DRV_1BIT,
                             73, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(78, "HSBCLKOUT", 0,
-                            74, UNIPHIER_PIN_DRV_4_8,
+                            74, UNIPHIER_PIN_DRV_1BIT,
                             74, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(79, "HSVALOUT", 0,
-                            75, UNIPHIER_PIN_DRV_4_8,
+                            75, UNIPHIER_PIN_DRV_1BIT,
                             75, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(80, "HSSYNCOUT", 0,
-                            76, UNIPHIER_PIN_DRV_4_8,
+                            76, UNIPHIER_PIN_DRV_1BIT,
                             76, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(81, "HS1DIN0", 0,
-                            77, UNIPHIER_PIN_DRV_4_8,
+                            77, UNIPHIER_PIN_DRV_1BIT,
                             77, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(82, "HS1DIN1", 0,
-                            78, UNIPHIER_PIN_DRV_4_8,
+                            78, UNIPHIER_PIN_DRV_1BIT,
                             78, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(83, "HS1DIN2", 0,
-                            79, UNIPHIER_PIN_DRV_4_8,
+                            79, UNIPHIER_PIN_DRV_1BIT,
                             79, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(84, "HS1DIN3", 0,
-                            80, UNIPHIER_PIN_DRV_4_8,
+                            80, UNIPHIER_PIN_DRV_1BIT,
                             80, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(85, "HS1DIN4", 0,
-                            81, UNIPHIER_PIN_DRV_4_8,
+                            81, UNIPHIER_PIN_DRV_1BIT,
                             81, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(86, "HS1DIN5", 0,
-                            82, UNIPHIER_PIN_DRV_4_8,
+                            82, UNIPHIER_PIN_DRV_1BIT,
                             82, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(87, "HS1DIN6", 0,
-                            83, UNIPHIER_PIN_DRV_4_8,
+                            83, UNIPHIER_PIN_DRV_1BIT,
                             83, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(88, "HS1DIN7", 0,
-                            84, UNIPHIER_PIN_DRV_4_8,
+                            84, UNIPHIER_PIN_DRV_1BIT,
                             84, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(89, "HS1BCLKIN", 0,
-                            85, UNIPHIER_PIN_DRV_4_8,
+                            85, UNIPHIER_PIN_DRV_1BIT,
                             85, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(90, "HS1VALIN", 0,
-                            86, UNIPHIER_PIN_DRV_4_8,
+                            86, UNIPHIER_PIN_DRV_1BIT,
                             86, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(91, "HS1SYNCIN", 0,
-                            87, UNIPHIER_PIN_DRV_4_8,
+                            87, UNIPHIER_PIN_DRV_1BIT,
                             87, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(92, "AGCI", 3,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             132, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(93, "AGCR", 4,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             133, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(94, "AGCBS", 5,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             134, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(95, "IECOUT", 0,
-                            88, UNIPHIER_PIN_DRV_4_8,
+                            88, UNIPHIER_PIN_DRV_1BIT,
                             88, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(96, "ASMCK", 0,
-                            89, UNIPHIER_PIN_DRV_4_8,
+                            89, UNIPHIER_PIN_DRV_1BIT,
                             89, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(97, "ABCKO", UNIPHIER_PIN_IECTRL_NONE,
-                            90, UNIPHIER_PIN_DRV_4_8,
+                            90, UNIPHIER_PIN_DRV_1BIT,
                             90, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(98, "ALRCKO", UNIPHIER_PIN_IECTRL_NONE,
-                            91, UNIPHIER_PIN_DRV_4_8,
+                            91, UNIPHIER_PIN_DRV_1BIT,
                             91, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(99, "ASDOUT0", UNIPHIER_PIN_IECTRL_NONE,
-                            92, UNIPHIER_PIN_DRV_4_8,
+                            92, UNIPHIER_PIN_DRV_1BIT,
                             92, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(100, "ASDOUT1", UNIPHIER_PIN_IECTRL_NONE,
-                            93, UNIPHIER_PIN_DRV_4_8,
+                            93, UNIPHIER_PIN_DRV_1BIT,
                             93, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(101, "ARCOUT", 0,
-                            94, UNIPHIER_PIN_DRV_4_8,
+                            94, UNIPHIER_PIN_DRV_1BIT,
                             94, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(102, "SDA0", 10,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(103, "SCL0", 10,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(104, "SDA1", 11,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(105, "SCL1", 11,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(106, "DMDSDA0", 12,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(107, "DMDSCL0", 12,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(108, "DMDSDA1", 13,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(109, "DMDSCL1", 13,
-                            -1, UNIPHIER_PIN_DRV_FIXED_4,
+                            -1, UNIPHIER_PIN_DRV_FIXED4,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(110, "SBO0", UNIPHIER_PIN_IECTRL_NONE,
-                            95, UNIPHIER_PIN_DRV_4_8,
+                            95, UNIPHIER_PIN_DRV_1BIT,
                             95, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(111, "SBI0", UNIPHIER_PIN_IECTRL_NONE,
-                            96, UNIPHIER_PIN_DRV_4_8,
+                            96, UNIPHIER_PIN_DRV_1BIT,
                             96, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(112, "SBO1", 0,
-                            97, UNIPHIER_PIN_DRV_4_8,
+                            97, UNIPHIER_PIN_DRV_1BIT,
                             97, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(113, "SBI1", 0,
-                            98, UNIPHIER_PIN_DRV_4_8,
+                            98, UNIPHIER_PIN_DRV_1BIT,
                             98, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(114, "TXD1", 0,
-                            99, UNIPHIER_PIN_DRV_4_8,
+                            99, UNIPHIER_PIN_DRV_1BIT,
                             99, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(115, "RXD1", 0,
-                            100, UNIPHIER_PIN_DRV_4_8,
+                            100, UNIPHIER_PIN_DRV_1BIT,
                             100, UNIPHIER_PIN_PULL_UP),
        UNIPHIER_PINCTRL_PIN(116, "HIN", 1,
-                            -1, UNIPHIER_PIN_DRV_FIXED_5,
+                            -1, UNIPHIER_PIN_DRV_FIXED5,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(117, "VIN", 2,
-                            -1, UNIPHIER_PIN_DRV_FIXED_5,
+                            -1, UNIPHIER_PIN_DRV_FIXED5,
                             -1, UNIPHIER_PIN_PULL_NONE),
        UNIPHIER_PINCTRL_PIN(118, "TCON0", 0,
-                            101, UNIPHIER_PIN_DRV_4_8,
+                            101, UNIPHIER_PIN_DRV_1BIT,
                             101, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(119, "TCON1", 0,
-                            102, UNIPHIER_PIN_DRV_4_8,
+                            102, UNIPHIER_PIN_DRV_1BIT,
                             102, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(120, "TCON2", 0,
-                            103, UNIPHIER_PIN_DRV_4_8,
+                            103, UNIPHIER_PIN_DRV_1BIT,
                             103, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(121, "TCON3", 0,
-                            104, UNIPHIER_PIN_DRV_4_8,
+                            104, UNIPHIER_PIN_DRV_1BIT,
                             104, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(122, "TCON4", 0,
-                            105, UNIPHIER_PIN_DRV_4_8,
+                            105, UNIPHIER_PIN_DRV_1BIT,
                             105, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(123, "TCON5", 0,
-                            106, UNIPHIER_PIN_DRV_4_8,
+                            106, UNIPHIER_PIN_DRV_1BIT,
                             106, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(124, "TCON6", 0,
-                            107, UNIPHIER_PIN_DRV_4_8,
+                            107, UNIPHIER_PIN_DRV_1BIT,
                             107, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(125, "TCON7", 0,
-                            108, UNIPHIER_PIN_DRV_4_8,
+                            108, UNIPHIER_PIN_DRV_1BIT,
                             108, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(126, "TCON8", 0,
-                            109, UNIPHIER_PIN_DRV_4_8,
+                            109, UNIPHIER_PIN_DRV_1BIT,
                             109, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(127, "PWMA", 0,
-                            110, UNIPHIER_PIN_DRV_4_8,
+                            110, UNIPHIER_PIN_DRV_1BIT,
                             110, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(128, "XIRQ0", 0,
-                            111, UNIPHIER_PIN_DRV_4_8,
+                            111, UNIPHIER_PIN_DRV_1BIT,
                             111, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(129, "XIRQ1", 0,
-                            112, UNIPHIER_PIN_DRV_4_8,
+                            112, UNIPHIER_PIN_DRV_1BIT,
                             112, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(130, "XIRQ2", 0,
-                            113, UNIPHIER_PIN_DRV_4_8,
+                            113, UNIPHIER_PIN_DRV_1BIT,
                             113, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(131, "XIRQ3", 0,
-                            114, UNIPHIER_PIN_DRV_4_8,
+                            114, UNIPHIER_PIN_DRV_1BIT,
                             114, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(132, "XIRQ4", 0,
-                            115, UNIPHIER_PIN_DRV_4_8,
+                            115, UNIPHIER_PIN_DRV_1BIT,
                             115, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(133, "XIRQ5", 0,
-                            116, UNIPHIER_PIN_DRV_4_8,
+                            116, UNIPHIER_PIN_DRV_1BIT,
                             116, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(134, "XIRQ6", 0,
-                            117, UNIPHIER_PIN_DRV_4_8,
+                            117, UNIPHIER_PIN_DRV_1BIT,
                             117, UNIPHIER_PIN_PULL_DOWN),
        UNIPHIER_PINCTRL_PIN(135, "XIRQ7", 0,
-                            118, UNIPHIER_PIN_DRV_4_8,
+                            118, UNIPHIER_PIN_DRV_1BIT,
                             118, UNIPHIER_PIN_PULL_DOWN),
+       /* dedicated pins */
+       UNIPHIER_PINCTRL_PIN(136, "ED0", -1,
+                            0, UNIPHIER_PIN_DRV_1BIT,
+                            0, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(137, "ED1", -1,
+                            1, UNIPHIER_PIN_DRV_1BIT,
+                            1, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(138, "ED2", -1,
+                            2, UNIPHIER_PIN_DRV_1BIT,
+                            2, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(139, "ED3", -1,
+                            3, UNIPHIER_PIN_DRV_1BIT,
+                            3, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(140, "ED4", -1,
+                            4, UNIPHIER_PIN_DRV_1BIT,
+                            4, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(141, "ED5", -1,
+                            5, UNIPHIER_PIN_DRV_1BIT,
+                            5, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(142, "ED6", -1,
+                            6, UNIPHIER_PIN_DRV_1BIT,
+                            6, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(143, "ED7", -1,
+                            7, UNIPHIER_PIN_DRV_1BIT,
+                            7, UNIPHIER_PIN_PULL_DOWN),
+       UNIPHIER_PINCTRL_PIN(144, "XERWE0", -1,
+                            8, UNIPHIER_PIN_DRV_1BIT,
+                            8, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(145, "XERWE1", -1,
+                            9, UNIPHIER_PIN_DRV_1BIT,
+                            9, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(146, "ERXW", -1,
+                            10, UNIPHIER_PIN_DRV_1BIT,
+                            10, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(147, "ES0", -1,
+                            11, UNIPHIER_PIN_DRV_1BIT,
+                            11, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(148, "ES1", -1,
+                            12, UNIPHIER_PIN_DRV_1BIT,
+                            12, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(149, "ES2", -1,
+                            13, UNIPHIER_PIN_DRV_1BIT,
+                            13, UNIPHIER_PIN_PULL_UP),
+       UNIPHIER_PINCTRL_PIN(150, "XECS1", -1,
+                            14, UNIPHIER_PIN_DRV_1BIT,
+                            14, UNIPHIER_PIN_PULL_DOWN),
 };
 
 static const unsigned emmc_pins[] = {21, 22, 23, 24, 25, 26, 27};
-static const unsigned emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1};
+static const int emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1};
 static const unsigned emmc_dat8_pins[] = {28, 29, 30, 31};
-static const unsigned emmc_dat8_muxvals[] = {1, 1, 1, 1};
+static const int emmc_dat8_muxvals[] = {1, 1, 1, 1};
+static const unsigned ether_mii_pins[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 13, 14,
+                                         61, 63, 64, 65, 66, 67, 68};
+static const int ether_mii_muxvals[] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+                                       13, 13, 27, 27, 27, 27, 27, 27, 27};
+static const unsigned ether_rmii_pins[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 13,
+                                          14};
+static const int ether_rmii_muxvals[] = {13, 13, 13, 13, 13, 13, 13, 13, 13,
+                                        13, 13, 13};
 static const unsigned i2c0_pins[] = {102, 103};
-static const unsigned i2c0_muxvals[] = {0, 0};
+static const int i2c0_muxvals[] = {0, 0};
 static const unsigned i2c1_pins[] = {104, 105};
-static const unsigned i2c1_muxvals[] = {0, 0};
+static const int i2c1_muxvals[] = {0, 0};
 static const unsigned i2c2_pins[] = {108, 109};
-static const unsigned i2c2_muxvals[] = {2, 2};
+static const int i2c2_muxvals[] = {2, 2};
 static const unsigned i2c3_pins[] = {108, 109};
-static const unsigned i2c3_muxvals[] = {3, 3};
+static const int i2c3_muxvals[] = {3, 3};
 static const unsigned nand_pins[] = {15, 16, 17, 18, 19, 20, 21, 24, 25, 26,
                                     27, 28, 29, 30, 31};
-static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                                       0, 0};
+static const int nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 static const unsigned nand_cs1_pins[] = {22, 23};
-static const unsigned nand_cs1_muxvals[] = {0, 0};
+static const int nand_cs1_muxvals[] = {0, 0};
 static const unsigned sd_pins[] = {32, 33, 34, 35, 36, 37, 38, 39, 40};
-static const unsigned sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const int sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned system_bus_pins[] = {136, 137, 138, 139, 140, 141, 142,
+                                          143, 144, 145, 146, 147, 148, 149};
+static const int system_bus_muxvals[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1,
+                                        -1, -1, -1, -1, -1};
+static const unsigned system_bus_cs1_pins[] = {150};
+static const int system_bus_cs1_muxvals[] = {-1};
+static const unsigned system_bus_cs2_pins[] = {10};
+static const int system_bus_cs2_muxvals[] = {1};
+static const unsigned system_bus_cs3_pins[] = {11};
+static const int system_bus_cs3_muxvals[] = {1};
+static const unsigned system_bus_cs4_pins[] = {12};
+static const int system_bus_cs4_muxvals[] = {1};
+static const unsigned system_bus_cs5_pins[] = {13};
+static const int system_bus_cs5_muxvals[] = {1};
 static const unsigned uart0_pins[] = {70, 71};
-static const unsigned uart0_muxvals[] = {3, 3};
+static const int uart0_muxvals[] = {3, 3};
 static const unsigned uart1_pins[] = {114, 115};
-static const unsigned uart1_muxvals[] = {0, 0};
+static const int uart1_muxvals[] = {0, 0};
 static const unsigned uart2_pins[] = {112, 113};
-static const unsigned uart2_muxvals[] = {1, 1};
+static const int uart2_muxvals[] = {1, 1};
 static const unsigned uart3_pins[] = {110, 111};
-static const unsigned uart3_muxvals[] = {1, 1};
+static const int uart3_muxvals[] = {1, 1};
 static const unsigned usb0_pins[] = {41, 42};
-static const unsigned usb0_muxvals[] = {0, 0};
+static const int usb0_muxvals[] = {0, 0};
 static const unsigned usb1_pins[] = {43, 44};
-static const unsigned usb1_muxvals[] = {0, 0};
+static const int usb1_muxvals[] = {0, 0};
 static const unsigned usb2_pins[] = {114, 115};
-static const unsigned usb2_muxvals[] = {1, 1};
+static const int usb2_muxvals[] = {1, 1};
 static const unsigned port_range0_pins[] = {
        0, 1, 2, 3, 4, 5, 6, 7,                         /* PORT0x */
        8, 9, 10, 11, 12, 13, 14, 15,                   /* PORT1x */
@@ -481,7 +546,7 @@ static const unsigned port_range0_pins[] = {
        48, 49, 46, 45, 123, 124, 125, 126,             /* PORT11x */
        47, 127, 20, 56, 22,                            /* PORT120-124 */
 };
-static const unsigned port_range0_muxvals[] = {
+static const int port_range0_muxvals[] = {
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT0x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT1x */
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT2x */
@@ -499,39 +564,41 @@ static const unsigned port_range0_muxvals[] = {
 static const unsigned port_range1_pins[] = {
        116, 117,                                       /* PORT130-131 */
 };
-static const unsigned port_range1_muxvals[] = {
+static const int port_range1_muxvals[] = {
        15, 15,                                         /* PORT130-131 */
 };
 static const unsigned port_range2_pins[] = {
        102, 103, 104, 105, 106, 107, 108, 109,         /* PORT14x */
 };
-static const unsigned port_range2_muxvals[] = {
+static const int port_range2_muxvals[] = {
        15, 15, 15, 15, 15, 15, 15, 15,                 /* PORT14x */
 };
 static const unsigned port_range3_pins[] = {
        23,                                             /* PORT166 */
 };
-static const unsigned port_range3_muxvals[] = {
+static const int port_range3_muxvals[] = {
        15,                                             /* PORT166 */
 };
 static const unsigned xirq_range0_pins[] = {
        128, 129, 130, 131, 132, 133, 134, 135,         /* XIRQ0-7 */
        82, 87, 88, 50, 51,                             /* XIRQ8-12 */
 };
-static const unsigned xirq_range0_muxvals[] = {
+static const int xirq_range0_muxvals[] = {
        0, 0, 0, 0, 0, 0, 0, 0,                         /* XIRQ0-7 */
        14, 14, 14, 14, 14,                             /* XIRQ8-12 */
 };
 static const unsigned xirq_range1_pins[] = {
        52, 58,                                         /* XIRQ14-15 */
 };
-static const unsigned xirq_range1_muxvals[] = {
+static const int xirq_range1_muxvals[] = {
        14, 14,                                         /* XIRQ14-15 */
 };
 
-static const struct uniphier_pinctrl_group ph1_sld8_groups[] = {
+static const struct uniphier_pinctrl_group uniphier_sld8_groups[] = {
        UNIPHIER_PINCTRL_GROUP(emmc),
        UNIPHIER_PINCTRL_GROUP(emmc_dat8),
+       UNIPHIER_PINCTRL_GROUP(ether_mii),
+       UNIPHIER_PINCTRL_GROUP(ether_rmii),
        UNIPHIER_PINCTRL_GROUP(i2c0),
        UNIPHIER_PINCTRL_GROUP(i2c1),
        UNIPHIER_PINCTRL_GROUP(i2c2),
@@ -539,6 +606,12 @@ static const struct uniphier_pinctrl_group ph1_sld8_groups[] = {
        UNIPHIER_PINCTRL_GROUP(nand),
        UNIPHIER_PINCTRL_GROUP(nand_cs1),
        UNIPHIER_PINCTRL_GROUP(sd),
+       UNIPHIER_PINCTRL_GROUP(system_bus),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs1),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs2),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs3),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs4),
+       UNIPHIER_PINCTRL_GROUP(system_bus_cs5),
        UNIPHIER_PINCTRL_GROUP(uart0),
        UNIPHIER_PINCTRL_GROUP(uart1),
        UNIPHIER_PINCTRL_GROUP(uart2),
@@ -682,12 +755,20 @@ static const struct uniphier_pinctrl_group ph1_sld8_groups[] = {
 };
 
 static const char * const emmc_groups[] = {"emmc", "emmc_dat8"};
+static const char * const ether_mii_groups[] = {"ether_mii"};
+static const char * const ether_rmii_groups[] = {"ether_rmii"};
 static const char * const i2c0_groups[] = {"i2c0"};
 static const char * const i2c1_groups[] = {"i2c1"};
 static const char * const i2c2_groups[] = {"i2c2"};
 static const char * const i2c3_groups[] = {"i2c3"};
 static const char * const nand_groups[] = {"nand", "nand_cs1"};
 static const char * const sd_groups[] = {"sd"};
+static const char * const system_bus_groups[] = {"system_bus",
+                                                "system_bus_cs1",
+                                                "system_bus_cs2",
+                                                "system_bus_cs3",
+                                                "system_bus_cs4",
+                                                "system_bus_cs5"};
 static const char * const uart0_groups[] = {"uart0"};
 static const char * const uart1_groups[] = {"uart1"};
 static const char * const uart2_groups[] = {"uart2"};
@@ -736,14 +817,17 @@ static const char * const xirq_groups[] = {
        "xirq12", /* none*/ "xirq14", "xirq15",
 };
 
-static const struct uniphier_pinmux_function ph1_sld8_functions[] = {
+static const struct uniphier_pinmux_function uniphier_sld8_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(emmc),
+       UNIPHIER_PINMUX_FUNCTION(ether_mii),
+       UNIPHIER_PINMUX_FUNCTION(ether_rmii),
        UNIPHIER_PINMUX_FUNCTION(i2c0),
        UNIPHIER_PINMUX_FUNCTION(i2c1),
        UNIPHIER_PINMUX_FUNCTION(i2c2),
        UNIPHIER_PINMUX_FUNCTION(i2c3),
        UNIPHIER_PINMUX_FUNCTION(nand),
        UNIPHIER_PINMUX_FUNCTION(sd),
+       UNIPHIER_PINMUX_FUNCTION(system_bus),
        UNIPHIER_PINMUX_FUNCTION(uart0),
        UNIPHIER_PINMUX_FUNCTION(uart1),
        UNIPHIER_PINMUX_FUNCTION(uart2),
@@ -755,43 +839,36 @@ static const struct uniphier_pinmux_function ph1_sld8_functions[] = {
        UNIPHIER_PINMUX_FUNCTION(xirq),
 };
 
-static struct uniphier_pinctrl_socdata ph1_sld8_pindata = {
-       .groups = ph1_sld8_groups,
-       .groups_count = ARRAY_SIZE(ph1_sld8_groups),
-       .functions = ph1_sld8_functions,
-       .functions_count = ARRAY_SIZE(ph1_sld8_functions),
-       .mux_bits = 8,
-       .reg_stride = 4,
-       .load_pinctrl = false,
-};
-
-static struct pinctrl_desc ph1_sld8_pinctrl_desc = {
-       .name = DRIVER_NAME,
-       .pins = ph1_sld8_pins,
-       .npins = ARRAY_SIZE(ph1_sld8_pins),
-       .owner = THIS_MODULE,
+static struct uniphier_pinctrl_socdata uniphier_sld8_pindata = {
+       .pins = uniphier_sld8_pins,
+       .npins = ARRAY_SIZE(uniphier_sld8_pins),
+       .groups = uniphier_sld8_groups,
+       .groups_count = ARRAY_SIZE(uniphier_sld8_groups),
+       .functions = uniphier_sld8_functions,
+       .functions_count = ARRAY_SIZE(uniphier_sld8_functions),
+       .caps = 0,
 };
 
-static int ph1_sld8_pinctrl_probe(struct platform_device *pdev)
+static int uniphier_sld8_pinctrl_probe(struct platform_device *pdev)
 {
-       return uniphier_pinctrl_probe(pdev, &ph1_sld8_pinctrl_desc,
-                                     &ph1_sld8_pindata);
+       return uniphier_pinctrl_probe(pdev, &uniphier_sld8_pindata);
 }
 
-static const struct of_device_id ph1_sld8_pinctrl_match[] = {
+static const struct of_device_id uniphier_sld8_pinctrl_match[] = {
+       { .compatible = "socionext,uniphier-sld8-pinctrl" },
        { .compatible = "socionext,ph1-sld8-pinctrl" },
        { /* sentinel */ }
 };
-MODULE_DEVICE_TABLE(of, ph1_sld8_pinctrl_match);
+MODULE_DEVICE_TABLE(of, uniphier_sld8_pinctrl_match);
 
-static struct platform_driver ph1_sld8_pinctrl_driver = {
-       .probe = ph1_sld8_pinctrl_probe,
+static struct platform_driver uniphier_sld8_pinctrl_driver = {
+       .probe = uniphier_sld8_pinctrl_probe,
        .driver = {
-               .name = DRIVER_NAME,
-               .of_match_table = ph1_sld8_pinctrl_match,
+               .name = "uniphier-sld8-pinctrl",
+               .of_match_table = uniphier_sld8_pinctrl_match,
        },
 };
-module_platform_driver(ph1_sld8_pinctrl_driver);
+module_platform_driver(uniphier_sld8_pinctrl_driver);
 
 MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
 MODULE_DESCRIPTION("UniPhier PH1-sLD8 pinctrl driver");
index a21154f..923f36c 100644 (file)
 #ifndef __PINCTRL_UNIPHIER_H__
 #define __PINCTRL_UNIPHIER_H__
 
+#include <linux/bitops.h>
 #include <linux/bug.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 
+struct platform_device;
+
 #define UNIPHIER_PINCTRL_PINMUX_BASE   0x0
 #define UNIPHIER_PINCTRL_LOAD_PINMUX   0x700
 #define UNIPHIER_PINCTRL_DRVCTRL_BASE  0x800
 #define UNIPHIER_PINCTRL_DRV2CTRL_BASE 0x900
+#define UNIPHIER_PINCTRL_DRV3CTRL_BASE 0x980
 #define UNIPHIER_PINCTRL_PUPDCTRL_BASE 0xa00
 #define UNIPHIER_PINCTRL_IECTRL                0xd00
 
 #define UNIPHIER_PIN_DRVCTRL_MASK      ((1UL << (UNIPHIER_PIN_DRVCTRL_BITS)) \
                                         - 1)
 
-/* supported drive strength (mA) */
-#define UNIPHIER_PIN_DRV_STR_SHIFT     ((UNIPHIER_PIN_DRVCTRL_SHIFT) + \
+/* drive control type */
+#define UNIPHIER_PIN_DRV_TYPE_SHIFT    ((UNIPHIER_PIN_DRVCTRL_SHIFT) + \
                                         (UNIPHIER_PIN_DRVCTRL_BITS))
-#define UNIPHIER_PIN_DRV_STR_BITS      3
-#define UNIPHIER_PIN_DRV_STR_MASK      ((1UL << (UNIPHIER_PIN_DRV_STR_BITS)) \
+#define UNIPHIER_PIN_DRV_TYPE_BITS     3
+#define UNIPHIER_PIN_DRV_TYPE_MASK     ((1UL << (UNIPHIER_PIN_DRV_TYPE_BITS)) \
                                         - 1)
 
 /* pull-up / pull-down register number */
-#define UNIPHIER_PIN_PUPDCTRL_SHIFT    ((UNIPHIER_PIN_DRV_STR_SHIFT) + \
-                                        (UNIPHIER_PIN_DRV_STR_BITS))
+#define UNIPHIER_PIN_PUPDCTRL_SHIFT    ((UNIPHIER_PIN_DRV_TYPE_SHIFT) + \
+                                        (UNIPHIER_PIN_DRV_TYPE_BITS))
 #define UNIPHIER_PIN_PUPDCTRL_BITS     9
 #define UNIPHIER_PIN_PUPDCTRL_MASK     ((1UL << (UNIPHIER_PIN_PUPDCTRL_BITS))\
                                         - 1)
 
 #define UNIPHIER_PIN_IECTRL_NONE       (UNIPHIER_PIN_IECTRL_MASK)
 
-/* selectable drive strength */
-enum uniphier_pin_drv_str {
-       UNIPHIER_PIN_DRV_4_8,           /* 2 level control: 4/8 mA */
-       UNIPHIER_PIN_DRV_8_12_16_20,    /* 4 level control: 8/12/16/20 mA */
-       UNIPHIER_PIN_DRV_FIXED_4,       /* fixed to 4mA */
-       UNIPHIER_PIN_DRV_FIXED_5,       /* fixed to 5mA */
-       UNIPHIER_PIN_DRV_FIXED_8,       /* fixed to 8mA */
+/* drive control type */
+enum uniphier_pin_drv_type {
+       UNIPHIER_PIN_DRV_1BIT,          /* 2 level control: 4/8 mA */
+       UNIPHIER_PIN_DRV_2BIT,          /* 4 level control: 8/12/16/20 mA */
+       UNIPHIER_PIN_DRV_3BIT,          /* 8 level control: 4/5/7/9/11/12/14/16 mA */
+       UNIPHIER_PIN_DRV_FIXED4,        /* fixed to 4mA */
+       UNIPHIER_PIN_DRV_FIXED5,        /* fixed to 5mA */
+       UNIPHIER_PIN_DRV_FIXED8,        /* fixed to 8mA */
        UNIPHIER_PIN_DRV_NONE,          /* no support (input only pin) */
 };
 
@@ -89,17 +94,17 @@ enum uniphier_pin_pull_dir {
        (((x) & (UNIPHIER_PIN_IECTRL_MASK)) << (UNIPHIER_PIN_IECTRL_SHIFT))
 #define UNIPHIER_PIN_DRVCTRL(x) \
        (((x) & (UNIPHIER_PIN_DRVCTRL_MASK)) << (UNIPHIER_PIN_DRVCTRL_SHIFT))
-#define UNIPHIER_PIN_DRV_STR(x) \
-       (((x) & (UNIPHIER_PIN_DRV_STR_MASK)) << (UNIPHIER_PIN_DRV_STR_SHIFT))
+#define UNIPHIER_PIN_DRV_TYPE(x) \
+       (((x) & (UNIPHIER_PIN_DRV_TYPE_MASK)) << (UNIPHIER_PIN_DRV_TYPE_SHIFT))
 #define UNIPHIER_PIN_PUPDCTRL(x) \
        (((x) & (UNIPHIER_PIN_PUPDCTRL_MASK)) << (UNIPHIER_PIN_PUPDCTRL_SHIFT))
 #define UNIPHIER_PIN_PULL_DIR(x) \
        (((x) & (UNIPHIER_PIN_PULL_DIR_MASK)) << (UNIPHIER_PIN_PULL_DIR_SHIFT))
 
-#define UNIPHIER_PIN_ATTR_PACKED(iectrl, drvctrl, drv_str, pupdctrl, pull_dir)\
+#define UNIPHIER_PIN_ATTR_PACKED(iectrl, drvctrl, drv_type, pupdctrl, pull_dir)\
                                (UNIPHIER_PIN_IECTRL(iectrl) |          \
                                 UNIPHIER_PIN_DRVCTRL(drvctrl) |        \
-                                UNIPHIER_PIN_DRV_STR(drv_str) |        \
+                                UNIPHIER_PIN_DRV_TYPE(drv_type) |      \
                                 UNIPHIER_PIN_PUPDCTRL(pupdctrl) |      \
                                 UNIPHIER_PIN_PULL_DIR(pull_dir))
 
@@ -115,10 +120,10 @@ static inline unsigned int uniphier_pin_get_drvctrl(void *drv_data)
                                                UNIPHIER_PIN_DRVCTRL_MASK;
 }
 
-static inline unsigned int uniphier_pin_get_drv_str(void *drv_data)
+static inline unsigned int uniphier_pin_get_drv_type(void *drv_data)
 {
-       return ((unsigned long)drv_data >> UNIPHIER_PIN_DRV_STR_SHIFT) &
-                                               UNIPHIER_PIN_DRV_STR_MASK;
+       return ((unsigned long)drv_data >> UNIPHIER_PIN_DRV_TYPE_SHIFT) &
+                                               UNIPHIER_PIN_DRV_TYPE_MASK;
 }
 
 static inline unsigned int uniphier_pin_get_pupdctrl(void *drv_data)
@@ -143,7 +148,7 @@ struct uniphier_pinctrl_group {
        const char *name;
        const unsigned *pins;
        unsigned num_pins;
-       const unsigned *muxvals;
+       const int *muxvals;
        enum uniphier_pinmux_gpio_range_type range_type;
 };
 
@@ -154,13 +159,15 @@ struct uniphier_pinmux_function {
 };
 
 struct uniphier_pinctrl_socdata {
+       const struct pinctrl_pin_desc *pins;
+       unsigned int npins;
        const struct uniphier_pinctrl_group *groups;
        int groups_count;
        const struct uniphier_pinmux_function *functions;
        int functions_count;
-       unsigned mux_bits;
-       unsigned reg_stride;
-       bool load_pinctrl;
+       unsigned int caps;
+#define UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL    BIT(1)
+#define UNIPHIER_PINCTRL_CAPS_DBGMUX_SEPARATE  BIT(0)
 };
 
 #define UNIPHIER_PINCTRL_PIN(a, b, c, d, e, f, g)                      \
@@ -205,11 +212,7 @@ struct uniphier_pinctrl_socdata {
                .num_groups = ARRAY_SIZE(func##_groups),                \
        }
 
-struct platform_device;
-struct pinctrl_desc;
-
 int uniphier_pinctrl_probe(struct platform_device *pdev,
-                          struct pinctrl_desc *desc,
                           struct uniphier_pinctrl_socdata *socdata);
 
 #endif /* __PINCTRL_UNIPHIER_H__ */
index 72e97d7..1a8bf76 100644 (file)
@@ -77,6 +77,20 @@ config DA8XX_REMOTEPROC
          It's safe to say n here if you're not interested in multimedia
          offloading.
 
+config QCOM_MDT_LOADER
+       tristate
+
+config QCOM_Q6V5_PIL
+       tristate "Qualcomm Hexagon V5 Peripherial Image Loader"
+       depends on OF && ARCH_QCOM
+       depends on QCOM_SMEM
+       select MFD_SYSCON
+       select QCOM_MDT_LOADER
+       select REMOTEPROC
+       help
+         Say y here to support the Qualcomm Peripherial Image Loader for the
+         Hexagon V5 based remote processors.
+
 config ST_REMOTEPROC
        tristate "ST remoteproc support"
        depends on ARCH_STI
index 279cb2e..92d3758 100644 (file)
@@ -11,4 +11,6 @@ obj-$(CONFIG_OMAP_REMOTEPROC)         += omap_remoteproc.o
 obj-$(CONFIG_STE_MODEM_RPROC)          += ste_modem_rproc.o
 obj-$(CONFIG_WKUP_M3_RPROC)            += wkup_m3_rproc.o
 obj-$(CONFIG_DA8XX_REMOTEPROC)         += da8xx_remoteproc.o
+obj-$(CONFIG_QCOM_MDT_LOADER)          += qcom_mdt_loader.o
+obj-$(CONFIG_QCOM_Q6V5_PIL)            += qcom_q6v5_pil.o
 obj-$(CONFIG_ST_REMOTEPROC)            += st_remoteproc.o
diff --git a/drivers/remoteproc/qcom_mdt_loader.c b/drivers/remoteproc/qcom_mdt_loader.c
new file mode 100644 (file)
index 0000000..114e8e4
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Qualcomm Peripheral Image Loader
+ *
+ * Copyright (C) 2016 Linaro Ltd
+ * Copyright (C) 2015 Sony Mobile Communications Inc
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/elf.h>
+#include <linux/firmware.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/remoteproc.h>
+#include <linux/slab.h>
+
+#include "remoteproc_internal.h"
+#include "qcom_mdt_loader.h"
+
+/**
+ * qcom_mdt_find_rsc_table() - provide dummy resource table for remoteproc
+ * @rproc:     remoteproc handle
+ * @fw:                firmware header
+ * @tablesz:   outgoing size of the table
+ *
+ * Returns a dummy table.
+ */
+struct resource_table *qcom_mdt_find_rsc_table(struct rproc *rproc,
+                                              const struct firmware *fw,
+                                              int *tablesz)
+{
+       static struct resource_table table = { .ver = 1, };
+
+       *tablesz = sizeof(table);
+       return &table;
+}
+EXPORT_SYMBOL_GPL(qcom_mdt_find_rsc_table);
+
+/**
+ * qcom_mdt_parse() - extract useful parameters from the mdt header
+ * @fw:                firmware handle
+ * @fw_addr:   optional reference for base of the firmware's memory region
+ * @fw_size:   optional reference for size of the firmware's memory region
+ * @fw_relocate: optional reference for flagging if the firmware is relocatable
+ *
+ * Returns 0 on success, negative errno otherwise.
+ */
+int qcom_mdt_parse(const struct firmware *fw, phys_addr_t *fw_addr,
+                  size_t *fw_size, bool *fw_relocate)
+{
+       const struct elf32_phdr *phdrs;
+       const struct elf32_phdr *phdr;
+       const struct elf32_hdr *ehdr;
+       phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX;
+       phys_addr_t max_addr = 0;
+       bool relocate = false;
+       int i;
+
+       ehdr = (struct elf32_hdr *)fw->data;
+       phdrs = (struct elf32_phdr *)(ehdr + 1);
+
+       for (i = 0; i < ehdr->e_phnum; i++) {
+               phdr = &phdrs[i];
+
+               if (phdr->p_type != PT_LOAD)
+                       continue;
+
+               if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
+                       continue;
+
+               if (!phdr->p_memsz)
+                       continue;
+
+               if (phdr->p_flags & QCOM_MDT_RELOCATABLE)
+                       relocate = true;
+
+               if (phdr->p_paddr < min_addr)
+                       min_addr = phdr->p_paddr;
+
+               if (phdr->p_paddr + phdr->p_memsz > max_addr)
+                       max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K);
+       }
+
+       if (fw_addr)
+               *fw_addr = min_addr;
+       if (fw_size)
+               *fw_size = max_addr - min_addr;
+       if (fw_relocate)
+               *fw_relocate = relocate;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_mdt_parse);
+
+/**
+ * qcom_mdt_load() - load the firmware which header is defined in fw
+ * @rproc:     rproc handle
+ * @fw:                frimware object for the header
+ * @firmware:  filename of the firmware, for building .bXX names
+ *
+ * Returns 0 on success, negative errno otherwise.
+ */
+int qcom_mdt_load(struct rproc *rproc,
+                 const struct firmware *fw,
+                 const char *firmware)
+{
+       const struct elf32_phdr *phdrs;
+       const struct elf32_phdr *phdr;
+       const struct elf32_hdr *ehdr;
+       size_t fw_name_len;
+       char *fw_name;
+       void *ptr;
+       int ret;
+       int i;
+
+       ehdr = (struct elf32_hdr *)fw->data;
+       phdrs = (struct elf32_phdr *)(ehdr + 1);
+
+       fw_name_len = strlen(firmware);
+       if (fw_name_len <= 4)
+               return -EINVAL;
+
+       fw_name = kstrdup(firmware, GFP_KERNEL);
+       if (!fw_name)
+               return -ENOMEM;
+
+       for (i = 0; i < ehdr->e_phnum; i++) {
+               phdr = &phdrs[i];
+
+               if (phdr->p_type != PT_LOAD)
+                       continue;
+
+               if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
+                       continue;
+
+               if (!phdr->p_memsz)
+                       continue;
+
+               ptr = rproc_da_to_va(rproc, phdr->p_paddr, phdr->p_memsz);
+               if (!ptr) {
+                       dev_err(&rproc->dev, "segment outside memory range\n");
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (phdr->p_filesz) {
+                       sprintf(fw_name + fw_name_len - 3, "b%02d", i);
+                       ret = request_firmware(&fw, fw_name, &rproc->dev);
+                       if (ret) {
+                               dev_err(&rproc->dev, "failed to load %s\n",
+                                       fw_name);
+                               break;
+                       }
+
+                       memcpy(ptr, fw->data, fw->size);
+
+                       release_firmware(fw);
+               }
+
+               if (phdr->p_memsz > phdr->p_filesz)
+                       memset(ptr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz);
+       }
+
+       kfree(fw_name);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_mdt_load);
+
+MODULE_DESCRIPTION("Firmware parser for Qualcomm MDT format");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/remoteproc/qcom_mdt_loader.h b/drivers/remoteproc/qcom_mdt_loader.h
new file mode 100644 (file)
index 0000000..c5d7122
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __QCOM_MDT_LOADER_H__
+#define __QCOM_MDT_LOADER_H__
+
+#define QCOM_MDT_TYPE_MASK     (7 << 24)
+#define QCOM_MDT_TYPE_HASH     (2 << 24)
+#define QCOM_MDT_RELOCATABLE   BIT(27)
+
+struct resource_table * qcom_mdt_find_rsc_table(struct rproc *rproc, const struct firmware *fw, int *tablesz);
+int qcom_mdt_load(struct rproc *rproc, const struct firmware *fw, const char *fw_name);
+
+int qcom_mdt_parse(const struct firmware *fw, phys_addr_t *fw_addr, size_t *fw_size, bool *fw_relocate);
+
+#endif
diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c
new file mode 100644 (file)
index 0000000..2479188
--- /dev/null
@@ -0,0 +1,908 @@
+/*
+ * Qualcomm Peripheral Image Loader
+ *
+ * Copyright (C) 2016 Linaro Ltd.
+ * Copyright (C) 2014 Sony Mobile Communications AB
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/remoteproc.h>
+#include <linux/reset.h>
+#include <linux/soc/qcom/smem.h>
+#include <linux/soc/qcom/smem_state.h>
+
+#include "remoteproc_internal.h"
+#include "qcom_mdt_loader.h"
+
+#include <linux/qcom_scm.h>
+
+#define MBA_FIRMWARE_NAME              "mba.b00"
+#define MPSS_FIRMWARE_NAME             "modem.mdt"
+
+#define MPSS_CRASH_REASON_SMEM         421
+
+/* RMB Status Register Values */
+#define RMB_PBL_SUCCESS                        0x1
+
+#define RMB_MBA_XPU_UNLOCKED           0x1
+#define RMB_MBA_XPU_UNLOCKED_SCRIBBLED 0x2
+#define RMB_MBA_META_DATA_AUTH_SUCCESS 0x3
+#define RMB_MBA_AUTH_COMPLETE          0x4
+
+/* PBL/MBA interface registers */
+#define RMB_MBA_IMAGE_REG              0x00
+#define RMB_PBL_STATUS_REG             0x04
+#define RMB_MBA_COMMAND_REG            0x08
+#define RMB_MBA_STATUS_REG             0x0C
+#define RMB_PMI_META_DATA_REG          0x10
+#define RMB_PMI_CODE_START_REG         0x14
+#define RMB_PMI_CODE_LENGTH_REG                0x18
+
+#define RMB_CMD_META_DATA_READY                0x1
+#define RMB_CMD_LOAD_READY             0x2
+
+/* QDSP6SS Register Offsets */
+#define QDSP6SS_RESET_REG              0x014
+#define QDSP6SS_GFMUX_CTL_REG          0x020
+#define QDSP6SS_PWR_CTL_REG            0x030
+
+/* AXI Halt Register Offsets */
+#define AXI_HALTREQ_REG                        0x0
+#define AXI_HALTACK_REG                        0x4
+#define AXI_IDLE_REG                   0x8
+
+#define HALT_ACK_TIMEOUT_MS            100
+
+/* QDSP6SS_RESET */
+#define Q6SS_STOP_CORE                 BIT(0)
+#define Q6SS_CORE_ARES                 BIT(1)
+#define Q6SS_BUS_ARES_ENABLE           BIT(2)
+
+/* QDSP6SS_GFMUX_CTL */
+#define Q6SS_CLK_ENABLE                        BIT(1)
+
+/* QDSP6SS_PWR_CTL */
+#define Q6SS_L2DATA_SLP_NRET_N_0       BIT(0)
+#define Q6SS_L2DATA_SLP_NRET_N_1       BIT(1)
+#define Q6SS_L2DATA_SLP_NRET_N_2       BIT(2)
+#define Q6SS_L2TAG_SLP_NRET_N          BIT(16)
+#define Q6SS_ETB_SLP_NRET_N            BIT(17)
+#define Q6SS_L2DATA_STBY_N             BIT(18)
+#define Q6SS_SLP_RET_N                 BIT(19)
+#define Q6SS_CLAMP_IO                  BIT(20)
+#define QDSS_BHS_ON                    BIT(21)
+#define QDSS_LDO_BYP                   BIT(22)
+
+struct q6v5 {
+       struct device *dev;
+       struct rproc *rproc;
+
+       void __iomem *reg_base;
+       void __iomem *rmb_base;
+
+       struct regmap *halt_map;
+       u32 halt_q6;
+       u32 halt_modem;
+       u32 halt_nc;
+
+       struct reset_control *mss_restart;
+
+       struct qcom_smem_state *state;
+       unsigned stop_bit;
+
+       struct regulator_bulk_data supply[4];
+
+       struct clk *ahb_clk;
+       struct clk *axi_clk;
+       struct clk *rom_clk;
+
+       struct completion start_done;
+       struct completion stop_done;
+       bool running;
+
+       phys_addr_t mba_phys;
+       void *mba_region;
+       size_t mba_size;
+
+       phys_addr_t mpss_phys;
+       phys_addr_t mpss_reloc;
+       void *mpss_region;
+       size_t mpss_size;
+};
+
+enum {
+       Q6V5_SUPPLY_CX,
+       Q6V5_SUPPLY_MX,
+       Q6V5_SUPPLY_MSS,
+       Q6V5_SUPPLY_PLL,
+};
+
+static int q6v5_regulator_init(struct q6v5 *qproc)
+{
+       int ret;
+
+       qproc->supply[Q6V5_SUPPLY_CX].supply = "cx";
+       qproc->supply[Q6V5_SUPPLY_MX].supply = "mx";
+       qproc->supply[Q6V5_SUPPLY_MSS].supply = "mss";
+       qproc->supply[Q6V5_SUPPLY_PLL].supply = "pll";
+
+       ret = devm_regulator_bulk_get(qproc->dev,
+                                     ARRAY_SIZE(qproc->supply), qproc->supply);
+       if (ret < 0) {
+               dev_err(qproc->dev, "failed to get supplies\n");
+               return ret;
+       }
+
+       regulator_set_load(qproc->supply[Q6V5_SUPPLY_CX].consumer, 100000);
+       regulator_set_load(qproc->supply[Q6V5_SUPPLY_MSS].consumer, 100000);
+       regulator_set_load(qproc->supply[Q6V5_SUPPLY_PLL].consumer, 10000);
+
+       return 0;
+}
+
+static int q6v5_regulator_enable(struct q6v5 *qproc)
+{
+       struct regulator *mss = qproc->supply[Q6V5_SUPPLY_MSS].consumer;
+       struct regulator *mx = qproc->supply[Q6V5_SUPPLY_MX].consumer;
+       int ret;
+
+       /* TODO: Q6V5_SUPPLY_CX is supposed to be set to super-turbo here */
+
+       ret = regulator_set_voltage(mx, 1050000, INT_MAX);
+       if (ret)
+               return ret;
+
+       regulator_set_voltage(mss, 1000000, 1150000);
+
+       return regulator_bulk_enable(ARRAY_SIZE(qproc->supply), qproc->supply);
+}
+
+static void q6v5_regulator_disable(struct q6v5 *qproc)
+{
+       struct regulator *mss = qproc->supply[Q6V5_SUPPLY_MSS].consumer;
+       struct regulator *mx = qproc->supply[Q6V5_SUPPLY_MX].consumer;
+
+       /* TODO: Q6V5_SUPPLY_CX corner votes should be released */
+
+       regulator_bulk_disable(ARRAY_SIZE(qproc->supply), qproc->supply);
+       regulator_set_voltage(mx, 0, INT_MAX);
+       regulator_set_voltage(mss, 0, 1150000);
+}
+
+static int q6v5_load(struct rproc *rproc, const struct firmware *fw)
+{
+       struct q6v5 *qproc = rproc->priv;
+
+       memcpy(qproc->mba_region, fw->data, fw->size);
+
+       return 0;
+}
+
+static const struct rproc_fw_ops q6v5_fw_ops = {
+       .find_rsc_table = qcom_mdt_find_rsc_table,
+       .load = q6v5_load,
+};
+
+static int q6v5_rmb_pbl_wait(struct q6v5 *qproc, int ms)
+{
+       unsigned long timeout;
+       s32 val;
+
+       timeout = jiffies + msecs_to_jiffies(ms);
+       for (;;) {
+               val = readl(qproc->rmb_base + RMB_PBL_STATUS_REG);
+               if (val)
+                       break;
+
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+
+               msleep(1);
+       }
+
+       return val;
+}
+
+static int q6v5_rmb_mba_wait(struct q6v5 *qproc, u32 status, int ms)
+{
+
+       unsigned long timeout;
+       s32 val;
+
+       timeout = jiffies + msecs_to_jiffies(ms);
+       for (;;) {
+               val = readl(qproc->rmb_base + RMB_MBA_STATUS_REG);
+               if (val < 0)
+                       break;
+
+               if (!status && val)
+                       break;
+               else if (status && val == status)
+                       break;
+
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+
+               msleep(1);
+       }
+
+       return val;
+}
+
+static int q6v5proc_reset(struct q6v5 *qproc)
+{
+       u32 val;
+       int ret;
+
+       /* Assert resets, stop core */
+       val = readl(qproc->reg_base + QDSP6SS_RESET_REG);
+       val |= (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE);
+       writel(val, qproc->reg_base + QDSP6SS_RESET_REG);
+
+       /* Enable power block headswitch, and wait for it to stabilize */
+       val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+       val |= QDSS_BHS_ON | QDSS_LDO_BYP;
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+       udelay(1);
+
+       /*
+        * Turn on memories. L2 banks should be done individually
+        * to minimize inrush current.
+        */
+       val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+       val |= Q6SS_SLP_RET_N | Q6SS_L2TAG_SLP_NRET_N |
+               Q6SS_ETB_SLP_NRET_N | Q6SS_L2DATA_STBY_N;
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+       val |= Q6SS_L2DATA_SLP_NRET_N_2;
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+       val |= Q6SS_L2DATA_SLP_NRET_N_1;
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+       val |= Q6SS_L2DATA_SLP_NRET_N_0;
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+
+       /* Remove IO clamp */
+       val &= ~Q6SS_CLAMP_IO;
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+
+       /* Bring core out of reset */
+       val = readl(qproc->reg_base + QDSP6SS_RESET_REG);
+       val &= ~Q6SS_CORE_ARES;
+       writel(val, qproc->reg_base + QDSP6SS_RESET_REG);
+
+       /* Turn on core clock */
+       val = readl(qproc->reg_base + QDSP6SS_GFMUX_CTL_REG);
+       val |= Q6SS_CLK_ENABLE;
+       writel(val, qproc->reg_base + QDSP6SS_GFMUX_CTL_REG);
+
+       /* Start core execution */
+       val = readl(qproc->reg_base + QDSP6SS_RESET_REG);
+       val &= ~Q6SS_STOP_CORE;
+       writel(val, qproc->reg_base + QDSP6SS_RESET_REG);
+
+       /* Wait for PBL status */
+       ret = q6v5_rmb_pbl_wait(qproc, 1000);
+       if (ret == -ETIMEDOUT) {
+               dev_err(qproc->dev, "PBL boot timed out\n");
+       } else if (ret != RMB_PBL_SUCCESS) {
+               dev_err(qproc->dev, "PBL returned unexpected status %d\n", ret);
+               ret = -EINVAL;
+       } else {
+               ret = 0;
+       }
+
+       return ret;
+}
+
+static void q6v5proc_halt_axi_port(struct q6v5 *qproc,
+                                  struct regmap *halt_map,
+                                  u32 offset)
+{
+       unsigned long timeout;
+       unsigned int val;
+       int ret;
+
+       /* Check if we're already idle */
+       ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
+       if (!ret && val)
+               return;
+
+       /* Assert halt request */
+       regmap_write(halt_map, offset + AXI_HALTREQ_REG, 1);
+
+       /* Wait for halt */
+       timeout = jiffies + msecs_to_jiffies(HALT_ACK_TIMEOUT_MS);
+       for (;;) {
+               ret = regmap_read(halt_map, offset + AXI_HALTACK_REG, &val);
+               if (ret || val || time_after(jiffies, timeout))
+                       break;
+
+               msleep(1);
+       }
+
+       ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
+       if (ret || !val)
+               dev_err(qproc->dev, "port failed halt\n");
+
+       /* Clear halt request (port will remain halted until reset) */
+       regmap_write(halt_map, offset + AXI_HALTREQ_REG, 0);
+}
+
+static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
+{
+       DEFINE_DMA_ATTRS(attrs);
+       dma_addr_t phys;
+       void *ptr;
+       int ret;
+
+       dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &attrs);
+       ptr = dma_alloc_attrs(qproc->dev, fw->size, &phys, GFP_KERNEL, &attrs);
+       if (!ptr) {
+               dev_err(qproc->dev, "failed to allocate mdt buffer\n");
+               return -ENOMEM;
+       }
+
+       memcpy(ptr, fw->data, fw->size);
+
+       writel(phys, qproc->rmb_base + RMB_PMI_META_DATA_REG);
+       writel(RMB_CMD_META_DATA_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG);
+
+       ret = q6v5_rmb_mba_wait(qproc, RMB_MBA_META_DATA_AUTH_SUCCESS, 1000);
+       if (ret == -ETIMEDOUT)
+               dev_err(qproc->dev, "MPSS header authentication timed out\n");
+       else if (ret < 0)
+               dev_err(qproc->dev, "MPSS header authentication failed: %d\n", ret);
+
+       dma_free_attrs(qproc->dev, fw->size, ptr, phys, &attrs);
+
+       return ret < 0 ? ret : 0;
+}
+
+static int q6v5_mpss_validate(struct q6v5 *qproc, const struct firmware *fw)
+{
+       const struct elf32_phdr *phdrs;
+       const struct elf32_phdr *phdr;
+       struct elf32_hdr *ehdr;
+       phys_addr_t boot_addr;
+       phys_addr_t fw_addr;
+       bool relocate;
+       size_t size;
+       int ret;
+       int i;
+
+       ret = qcom_mdt_parse(fw, &fw_addr, NULL, &relocate);
+       if (ret) {
+               dev_err(qproc->dev, "failed to parse mdt header\n");
+               return ret;
+       }
+
+       if (relocate)
+               boot_addr = qproc->mpss_phys;
+       else
+               boot_addr = fw_addr;
+
+       ehdr = (struct elf32_hdr *)fw->data;
+       phdrs = (struct elf32_phdr *)(ehdr + 1);
+       for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
+               phdr = &phdrs[i];
+
+               if (phdr->p_type != PT_LOAD)
+                       continue;
+
+               if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
+                       continue;
+
+               if (!phdr->p_memsz)
+                       continue;
+
+               size = readl(qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
+               if (!size) {
+                       writel(boot_addr, qproc->rmb_base + RMB_PMI_CODE_START_REG);
+                       writel(RMB_CMD_LOAD_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG);
+               }
+
+               size += phdr->p_memsz;
+               writel(size, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
+       }
+
+       ret = q6v5_rmb_mba_wait(qproc, RMB_MBA_AUTH_COMPLETE, 10000);
+       if (ret == -ETIMEDOUT)
+               dev_err(qproc->dev, "MPSS authentication timed out\n");
+       else if (ret < 0)
+               dev_err(qproc->dev, "MPSS authentication failed: %d\n", ret);
+
+       return ret < 0 ? ret : 0;
+}
+
+static int q6v5_mpss_load(struct q6v5 *qproc)
+{
+       const struct firmware *fw;
+       phys_addr_t fw_addr;
+       bool relocate;
+       int ret;
+
+       ret = request_firmware(&fw, MPSS_FIRMWARE_NAME, qproc->dev);
+       if (ret < 0) {
+               dev_err(qproc->dev, "unable to load " MPSS_FIRMWARE_NAME "\n");
+               return ret;
+       }
+
+       ret = qcom_mdt_parse(fw, &fw_addr, NULL, &relocate);
+       if (ret) {
+               dev_err(qproc->dev, "failed to parse mdt header\n");
+               goto release_firmware;
+       }
+
+       if (relocate)
+               qproc->mpss_reloc = fw_addr;
+
+       /* Initialize the RMB validator */
+       writel(0, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
+
+       ret = q6v5_mpss_init_image(qproc, fw);
+       if (ret)
+               goto release_firmware;
+
+       ret = qcom_mdt_load(qproc->rproc, fw, MPSS_FIRMWARE_NAME);
+       if (ret)
+               goto release_firmware;
+
+       ret = q6v5_mpss_validate(qproc, fw);
+
+release_firmware:
+       release_firmware(fw);
+
+       return ret < 0 ? ret : 0;
+}
+
+static int q6v5_start(struct rproc *rproc)
+{
+       struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
+       int ret;
+
+       ret = q6v5_regulator_enable(qproc);
+       if (ret) {
+               dev_err(qproc->dev, "failed to enable supplies\n");
+               return ret;
+       }
+
+       ret = reset_control_deassert(qproc->mss_restart);
+       if (ret) {
+               dev_err(qproc->dev, "failed to deassert mss restart\n");
+               goto disable_vdd;
+       }
+
+       ret = clk_prepare_enable(qproc->ahb_clk);
+       if (ret)
+               goto assert_reset;
+
+       ret = clk_prepare_enable(qproc->axi_clk);
+       if (ret)
+               goto disable_ahb_clk;
+
+       ret = clk_prepare_enable(qproc->rom_clk);
+       if (ret)
+               goto disable_axi_clk;
+
+       writel(qproc->mba_phys, qproc->rmb_base + RMB_MBA_IMAGE_REG);
+
+       ret = q6v5proc_reset(qproc);
+       if (ret)
+               goto halt_axi_ports;
+
+       ret = q6v5_rmb_mba_wait(qproc, 0, 5000);
+       if (ret == -ETIMEDOUT) {
+               dev_err(qproc->dev, "MBA boot timed out\n");
+               goto halt_axi_ports;
+       } else if (ret != RMB_MBA_XPU_UNLOCKED &&
+                  ret != RMB_MBA_XPU_UNLOCKED_SCRIBBLED) {
+               dev_err(qproc->dev, "MBA returned unexpected status %d\n", ret);
+               ret = -EINVAL;
+               goto halt_axi_ports;
+       }
+
+       dev_info(qproc->dev, "MBA booted, loading mpss\n");
+
+       ret = q6v5_mpss_load(qproc);
+       if (ret)
+               goto halt_axi_ports;
+
+       ret = wait_for_completion_timeout(&qproc->start_done,
+                                         msecs_to_jiffies(5000));
+       if (ret == 0) {
+               dev_err(qproc->dev, "start timed out\n");
+               ret = -ETIMEDOUT;
+               goto halt_axi_ports;
+       }
+
+       qproc->running = true;
+
+       /* TODO: All done, release the handover resources */
+
+       return 0;
+
+halt_axi_ports:
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6);
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
+
+       clk_disable_unprepare(qproc->rom_clk);
+disable_axi_clk:
+       clk_disable_unprepare(qproc->axi_clk);
+disable_ahb_clk:
+       clk_disable_unprepare(qproc->ahb_clk);
+assert_reset:
+       reset_control_assert(qproc->mss_restart);
+disable_vdd:
+       q6v5_regulator_disable(qproc);
+
+       return ret;
+}
+
+static int q6v5_stop(struct rproc *rproc)
+{
+       struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
+       int ret;
+
+       qproc->running = false;
+
+       qcom_smem_state_update_bits(qproc->state,
+                                   BIT(qproc->stop_bit), BIT(qproc->stop_bit));
+
+       ret = wait_for_completion_timeout(&qproc->stop_done,
+                                         msecs_to_jiffies(5000));
+       if (ret == 0)
+               dev_err(qproc->dev, "timed out on wait\n");
+
+       qcom_smem_state_update_bits(qproc->state, BIT(qproc->stop_bit), 0);
+
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6);
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
+
+       reset_control_assert(qproc->mss_restart);
+       clk_disable_unprepare(qproc->rom_clk);
+       clk_disable_unprepare(qproc->axi_clk);
+       clk_disable_unprepare(qproc->ahb_clk);
+       q6v5_regulator_disable(qproc);
+
+       return 0;
+}
+
+static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
+{
+       struct q6v5 *qproc = rproc->priv;
+       int offset;
+
+       offset = da - qproc->mpss_reloc;
+       if (offset < 0 || offset + len > qproc->mpss_size)
+               return NULL;
+
+       return qproc->mpss_region + offset;
+}
+
+static const struct rproc_ops q6v5_ops = {
+       .start = q6v5_start,
+       .stop = q6v5_stop,
+       .da_to_va = q6v5_da_to_va,
+};
+
+static irqreturn_t q6v5_wdog_interrupt(int irq, void *dev)
+{
+       struct q6v5 *qproc = dev;
+       size_t len;
+       char *msg;
+
+       /* Sometimes the stop triggers a watchdog rather than a stop-ack */
+       if (!qproc->running) {
+               complete(&qproc->stop_done);
+               return IRQ_HANDLED;
+       }
+
+       msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, MPSS_CRASH_REASON_SMEM, &len);
+       if (!IS_ERR(msg) && len > 0 && msg[0])
+               dev_err(qproc->dev, "watchdog received: %s\n", msg);
+       else
+               dev_err(qproc->dev, "watchdog without message\n");
+
+       rproc_report_crash(qproc->rproc, RPROC_WATCHDOG);
+
+       if (!IS_ERR(msg))
+               msg[0] = '\0';
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t q6v5_fatal_interrupt(int irq, void *dev)
+{
+       struct q6v5 *qproc = dev;
+       size_t len;
+       char *msg;
+
+       msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, MPSS_CRASH_REASON_SMEM, &len);
+       if (!IS_ERR(msg) && len > 0 && msg[0])
+               dev_err(qproc->dev, "fatal error received: %s\n", msg);
+       else
+               dev_err(qproc->dev, "fatal error without message\n");
+
+       rproc_report_crash(qproc->rproc, RPROC_FATAL_ERROR);
+
+       if (!IS_ERR(msg))
+               msg[0] = '\0';
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t q6v5_handover_interrupt(int irq, void *dev)
+{
+       struct q6v5 *qproc = dev;
+
+       complete(&qproc->start_done);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t q6v5_stop_ack_interrupt(int irq, void *dev)
+{
+       struct q6v5 *qproc = dev;
+
+       complete(&qproc->stop_done);
+       return IRQ_HANDLED;
+}
+
+static int q6v5_init_mem(struct q6v5 *qproc, struct platform_device *pdev)
+{
+       struct of_phandle_args args;
+       struct resource *res;
+       int ret;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6");
+       qproc->reg_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(qproc->reg_base))
+               return PTR_ERR(qproc->reg_base);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb");
+       qproc->rmb_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(qproc->rmb_base))
+               return PTR_ERR(qproc->rmb_base);
+
+       ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
+                                              "qcom,halt-regs", 3, 0, &args);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
+               return -EINVAL;
+       }
+
+       qproc->halt_map = syscon_node_to_regmap(args.np);
+       of_node_put(args.np);
+       if (IS_ERR(qproc->halt_map))
+               return PTR_ERR(qproc->halt_map);
+
+       qproc->halt_q6 = args.args[0];
+       qproc->halt_modem = args.args[1];
+       qproc->halt_nc = args.args[2];
+
+       return 0;
+}
+
+static int q6v5_init_clocks(struct q6v5 *qproc)
+{
+       qproc->ahb_clk = devm_clk_get(qproc->dev, "iface");
+       if (IS_ERR(qproc->ahb_clk)) {
+               dev_err(qproc->dev, "failed to get iface clock\n");
+               return PTR_ERR(qproc->ahb_clk);
+       }
+
+       qproc->axi_clk = devm_clk_get(qproc->dev, "bus");
+       if (IS_ERR(qproc->axi_clk)) {
+               dev_err(qproc->dev, "failed to get bus clock\n");
+               return PTR_ERR(qproc->axi_clk);
+       }
+
+       qproc->rom_clk = devm_clk_get(qproc->dev, "mem");
+       if (IS_ERR(qproc->rom_clk)) {
+               dev_err(qproc->dev, "failed to get mem clock\n");
+               return PTR_ERR(qproc->rom_clk);
+       }
+
+       return 0;
+}
+
+static int q6v5_init_reset(struct q6v5 *qproc)
+{
+       qproc->mss_restart = devm_reset_control_get(qproc->dev, NULL);
+       if (IS_ERR(qproc->mss_restart)) {
+               dev_err(qproc->dev, "failed to acquire mss restart\n");
+               return PTR_ERR(qproc->mss_restart);
+       }
+
+       return 0;
+}
+
+static int q6v5_request_irq(struct q6v5 *qproc,
+                            struct platform_device *pdev,
+                            const char *name,
+                            irq_handler_t thread_fn)
+{
+       int ret;
+
+       ret = platform_get_irq_byname(pdev, name);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "no %s IRQ defined\n", name);
+               return ret;
+       }
+
+       ret = devm_request_threaded_irq(&pdev->dev, ret,
+                                       NULL, thread_fn,
+                                       IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                                       "q6v5", qproc);
+       if (ret)
+               dev_err(&pdev->dev, "request %s IRQ failed\n", name);
+
+       return ret;
+}
+
+static int q6v5_alloc_memory_region(struct q6v5 *qproc)
+{
+       struct device_node *child;
+       struct device_node *node;
+       struct resource r;
+       int ret;
+
+       child = of_get_child_by_name(qproc->dev->of_node, "mba");
+       node = of_parse_phandle(child, "memory-region", 0);
+       ret = of_address_to_resource(node, 0, &r);
+       if (ret) {
+               dev_err(qproc->dev, "unable to resolve mba region\n");
+               return ret;
+       }
+
+       qproc->mba_phys = r.start;
+       qproc->mba_size = resource_size(&r);
+       qproc->mba_region = devm_ioremap_wc(qproc->dev, qproc->mba_phys, qproc->mba_size);
+       if (!qproc->mba_region) {
+               dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n",
+                       &r.start, qproc->mba_size);
+               return -EBUSY;
+       }
+
+       child = of_get_child_by_name(qproc->dev->of_node, "mpss");
+       node = of_parse_phandle(child, "memory-region", 0);
+       ret = of_address_to_resource(node, 0, &r);
+       if (ret) {
+               dev_err(qproc->dev, "unable to resolve mpss region\n");
+               return ret;
+       }
+
+       qproc->mpss_phys = qproc->mpss_reloc = r.start;
+       qproc->mpss_size = resource_size(&r);
+       qproc->mpss_region = devm_ioremap_wc(qproc->dev, qproc->mpss_phys, qproc->mpss_size);
+       if (!qproc->mpss_region) {
+               dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n",
+                       &r.start, qproc->mpss_size);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int q6v5_probe(struct platform_device *pdev)
+{
+       struct q6v5 *qproc;
+       struct rproc *rproc;
+       int ret;
+
+       rproc = rproc_alloc(&pdev->dev, pdev->name, &q6v5_ops,
+                           MBA_FIRMWARE_NAME, sizeof(*qproc));
+       if (!rproc) {
+               dev_err(&pdev->dev, "failed to allocate rproc\n");
+               return -ENOMEM;
+       }
+
+       rproc->fw_ops = &q6v5_fw_ops;
+
+       qproc = (struct q6v5 *)rproc->priv;
+       qproc->dev = &pdev->dev;
+       qproc->rproc = rproc;
+       platform_set_drvdata(pdev, qproc);
+
+       init_completion(&qproc->start_done);
+       init_completion(&qproc->stop_done);
+
+       ret = q6v5_init_mem(qproc, pdev);
+       if (ret)
+               goto free_rproc;
+
+       ret = q6v5_alloc_memory_region(qproc);
+       if (ret)
+               goto free_rproc;
+
+       ret = q6v5_init_clocks(qproc);
+       if (ret)
+               goto free_rproc;
+
+       ret = q6v5_regulator_init(qproc);
+       if (ret)
+               goto free_rproc;
+
+       ret = q6v5_init_reset(qproc);
+       if (ret)
+               goto free_rproc;
+
+       ret = q6v5_request_irq(qproc, pdev, "wdog", q6v5_wdog_interrupt);
+       if (ret < 0)
+               goto free_rproc;
+
+       ret = q6v5_request_irq(qproc, pdev, "fatal", q6v5_fatal_interrupt);
+       if (ret < 0)
+               goto free_rproc;
+
+       ret = q6v5_request_irq(qproc, pdev, "handover", q6v5_handover_interrupt);
+       if (ret < 0)
+               goto free_rproc;
+
+       ret = q6v5_request_irq(qproc, pdev, "stop-ack", q6v5_stop_ack_interrupt);
+       if (ret < 0)
+               goto free_rproc;
+
+       qproc->state = qcom_smem_state_get(&pdev->dev, "stop", &qproc->stop_bit);
+       if (IS_ERR(qproc->state))
+               goto free_rproc;
+
+       ret = rproc_add(rproc);
+       if (ret)
+               goto free_rproc;
+
+       return 0;
+
+free_rproc:
+       rproc_put(rproc);
+
+       return ret;
+}
+
+static int q6v5_remove(struct platform_device *pdev)
+{
+       struct q6v5 *qproc = platform_get_drvdata(pdev);
+
+       rproc_del(qproc->rproc);
+       rproc_put(qproc->rproc);
+
+       return 0;
+}
+
+static const struct of_device_id q6v5_of_match[] = {
+       { .compatible = "qcom,q6v5-pil", },
+       { },
+};
+
+static struct platform_driver q6v5_driver = {
+       .probe = q6v5_probe,
+       .remove = q6v5_remove,
+       .driver = {
+               .name = "qcom-q6v5-pil",
+               .of_match_table = q6v5_of_match,
+       },
+};
+module_platform_driver(q6v5_driver);
+
+MODULE_DESCRIPTION("Peripheral Image Loader for Hexagon");
+MODULE_LICENSE("GPL v2");
index db3958b..fe0539e 100644 (file)
@@ -1264,11 +1264,6 @@ int rproc_add(struct rproc *rproc)
        if (ret < 0)
                return ret;
 
-       /* expose to rproc_get_by_phandle users */
-       mutex_lock(&rproc_list_mutex);
-       list_add(&rproc->node, &rproc_list);
-       mutex_unlock(&rproc_list_mutex);
-
        dev_info(dev, "%s is available\n", rproc->name);
 
        dev_info(dev, "Note: remoteproc is still under development and considered experimental.\n");
@@ -1276,8 +1271,16 @@ int rproc_add(struct rproc *rproc)
 
        /* create debugfs entries */
        rproc_create_debug_dir(rproc);
+       ret = rproc_add_virtio_devices(rproc);
+       if (ret < 0)
+               return ret;
 
-       return rproc_add_virtio_devices(rproc);
+       /* expose to rproc_get_by_phandle users */
+       mutex_lock(&rproc_list_mutex);
+       list_add(&rproc->node, &rproc_list);
+       mutex_unlock(&rproc_list_mutex);
+
+       return 0;
 }
 EXPORT_SYMBOL(rproc_add);
 
index fac1b51..9d66b4f 100644 (file)
@@ -31,7 +31,7 @@ static void dcssblk_release(struct gendisk *disk, fmode_t mode);
 static blk_qc_t dcssblk_make_request(struct request_queue *q,
                                                struct bio *bio);
 static long dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
-                        void __pmem **kaddr, pfn_t *pfn, long size);
+                        void **kaddr, pfn_t *pfn, long size);
 
 static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0";
 
@@ -884,7 +884,7 @@ fail:
 
 static long
 dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
-                       void __pmem **kaddr, pfn_t *pfn, long size)
+                       void **kaddr, pfn_t *pfn, long size)
 {
        struct dcssblk_dev_info *dev_info;
        unsigned long offset, dev_sz;
@@ -894,7 +894,7 @@ dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
                return -ENODEV;
        dev_sz = dev_info->end - dev_info->start;
        offset = secnum * 512;
-       *kaddr = (void __pmem *) (dev_info->start + offset);
+       *kaddr = (void *) dev_info->start + offset;
        *pfn = __pfn_to_pfn_t(PFN_DOWN(dev_info->start + offset), PFN_DEV);
 
        return dev_sz - offset;
index 59c4778..6201dce 100644 (file)
@@ -1183,7 +1183,6 @@ static const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8, 0x410000AC,
 #define CRB_NIU_XG_PAUSE_CTL_P1        0x8
 
 #define qla82xx_get_temp_val(x)          ((x) >> 16)
-#define qla82xx_get_temp_val1(x)          ((x) && 0x0000FFFF)
 #define qla82xx_get_temp_state(x)        ((x) & 0xffff)
 #define qla82xx_encode_temp(val, state)  (((val) << 16) | (state))
 
index 24d2745..45a1b4e 100644 (file)
@@ -72,10 +72,10 @@ static unsigned long lowmem_deathpending_timeout;
 static unsigned long lowmem_count(struct shrinker *s,
                                  struct shrink_control *sc)
 {
-       return global_page_state(NR_ACTIVE_ANON) +
-               global_page_state(NR_ACTIVE_FILE) +
-               global_page_state(NR_INACTIVE_ANON) +
-               global_page_state(NR_INACTIVE_FILE);
+       return global_node_page_state(NR_ACTIVE_ANON) +
+               global_node_page_state(NR_ACTIVE_FILE) +
+               global_node_page_state(NR_INACTIVE_ANON) +
+               global_node_page_state(NR_INACTIVE_FILE);
 }
 
 static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
@@ -91,8 +91,8 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
        short selected_oom_score_adj;
        int array_size = ARRAY_SIZE(lowmem_adj);
        int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages;
-       int other_file = global_page_state(NR_FILE_PAGES) -
-                                               global_page_state(NR_SHMEM) -
+       int other_file = global_node_page_state(NR_FILE_PAGES) -
+                                               global_node_page_state(NR_SHMEM) -
                                                total_swapcache_pages();
 
        if (lowmem_adj_size < array_size)
index f775242..8e52722 100644 (file)
@@ -170,7 +170,8 @@ static inline int is_omitted_entry(struct ll_statahead_info *sai, __u64 index)
  * Insert it into sai_entries tail when init.
  */
 static struct ll_sa_entry *
-ll_sa_entry_alloc(struct ll_statahead_info *sai, __u64 index,
+ll_sa_entry_alloc(struct dentry *parent,
+                 struct ll_statahead_info *sai, __u64 index,
                  const char *name, int len)
 {
        struct ll_inode_info *lli;
@@ -217,7 +218,8 @@ ll_sa_entry_alloc(struct ll_statahead_info *sai, __u64 index,
        dname = (char *)entry + sizeof(struct ll_sa_entry);
        memcpy(dname, name, len);
        dname[len] = 0;
-       entry->se_qstr.hash = full_name_hash(name, len);
+
+       entry->se_qstr.hash = full_name_hash(parent, name, len);
        entry->se_qstr.len = len;
        entry->se_qstr.name = dname;
 
@@ -898,7 +900,7 @@ static void ll_statahead_one(struct dentry *parent, const char *entry_name,
        int                    rc;
        int                    rc1;
 
-       entry = ll_sa_entry_alloc(sai, sai->sai_index, entry_name,
+       entry = ll_sa_entry_alloc(parent, sai, sai->sai_index, entry_name,
                                  entry_name_len);
        if (IS_ERR(entry))
                return;
index d1a7d6b..d011135 100644 (file)
@@ -1864,7 +1864,8 @@ void osc_dec_unstable_pages(struct ptlrpc_request *req)
        LASSERT(page_count >= 0);
 
        for (i = 0; i < page_count; i++)
-               dec_zone_page_state(desc->bd_iov[i].kiov_page, NR_UNSTABLE_NFS);
+               dec_node_page_state(desc->bd_iov[i].kiov_page,
+                                                       NR_UNSTABLE_NFS);
 
        atomic_sub(page_count, &cli->cl_cache->ccc_unstable_nr);
        LASSERT(atomic_read(&cli->cl_cache->ccc_unstable_nr) >= 0);
@@ -1898,7 +1899,8 @@ void osc_inc_unstable_pages(struct ptlrpc_request *req)
        LASSERT(page_count >= 0);
 
        for (i = 0; i < page_count; i++)
-               inc_zone_page_state(desc->bd_iov[i].kiov_page, NR_UNSTABLE_NFS);
+               inc_node_page_state(desc->bd_iov[i].kiov_page,
+                                                       NR_UNSTABLE_NFS);
 
        LASSERT(atomic_read(&cli->cl_cache->ccc_unstable_nr) >= 0);
        atomic_add(page_count, &cli->cl_cache->ccc_unstable_nr);
index 6e70597..eb8f8d3 100644 (file)
@@ -79,15 +79,6 @@ config USB_LCD
          To compile this driver as a module, choose M here: the
          module will be called usblcd.
 
-config USB_LED
-       tristate "USB LED driver support"
-       help
-         Say Y here if you want to connect an USBLED device to your 
-         computer's USB port.
-
-         To compile this driver as a module, choose M here: the
-         module will be called usbled.
-
 config USB_CYPRESS_CY7C63
        tristate "Cypress CY7C63xxx USB driver support"
        help
index 2769cf6..3d79faa 100644 (file)
@@ -15,7 +15,6 @@ obj-$(CONFIG_USB_IOWARRIOR)           += iowarrior.o
 obj-$(CONFIG_USB_ISIGHTFW)             += isight_firmware.o
 obj-$(CONFIG_USB_LCD)                  += usblcd.o
 obj-$(CONFIG_USB_LD)                   += ldusb.o
-obj-$(CONFIG_USB_LED)                  += usbled.o
 obj-$(CONFIG_USB_LEGOTOWER)            += legousbtower.o
 obj-$(CONFIG_USB_RIO500)               += rio500.o
 obj-$(CONFIG_USB_TEST)                 += usbtest.o
diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c
deleted file mode 100644 (file)
index bdef0d6..0000000
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * USB LED driver
- *
- * Copyright (C) 2004 Greg Kroah-Hartman (greg@kroah.com)
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation, version 2.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-
-
-#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com"
-#define DRIVER_DESC "USB LED Driver"
-
-enum led_type {
-       DELCOM_VISUAL_SIGNAL_INDICATOR,
-       DREAM_CHEEKY_WEBMAIL_NOTIFIER,
-       RISO_KAGAKU_LED
-};
-
-/* the Webmail LED made by RISO KAGAKU CORP. decodes a color index
-   internally, we want to keep the red+green+blue sysfs api, so we decode
-   from 1-bit RGB to the riso kagaku color index according to this table... */
-
-static unsigned const char riso_kagaku_tbl[] = {
-/* R+2G+4B -> riso kagaku color index */
-       [0] = 0, /* black   */
-       [1] = 2, /* red     */
-       [2] = 1, /* green   */
-       [3] = 5, /* yellow  */
-       [4] = 3, /* blue    */
-       [5] = 6, /* magenta */
-       [6] = 4, /* cyan    */
-       [7] = 7  /* white   */
-};
-
-#define RISO_KAGAKU_IX(r,g,b) riso_kagaku_tbl[((r)?1:0)+((g)?2:0)+((b)?4:0)]
-
-/* table of devices that work with this driver */
-static const struct usb_device_id id_table[] = {
-       { USB_DEVICE(0x0fc5, 0x1223),
-                       .driver_info = DELCOM_VISUAL_SIGNAL_INDICATOR },
-       { USB_DEVICE(0x1d34, 0x0004),
-                       .driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER },
-       { USB_DEVICE(0x1d34, 0x000a),
-                       .driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER },
-       { USB_DEVICE(0x1294, 0x1320),
-                       .driver_info = RISO_KAGAKU_LED },
-       { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-struct usb_led {
-       struct usb_device       *udev;
-       unsigned char           blue;
-       unsigned char           red;
-       unsigned char           green;
-       enum led_type           type;
-};
-
-static void change_color(struct usb_led *led)
-{
-       int retval = 0;
-       unsigned char *buffer;
-       int actlength;
-
-       buffer = kmalloc(8, GFP_KERNEL);
-       if (!buffer) {
-               dev_err(&led->udev->dev, "out of memory\n");
-               return;
-       }
-
-       switch (led->type) {
-       case DELCOM_VISUAL_SIGNAL_INDICATOR: {
-               unsigned char color = 0x07;
-
-               if (led->blue)
-                       color &= ~0x04;
-               if (led->red)
-                       color &= ~0x02;
-               if (led->green)
-                       color &= ~0x01;
-               dev_dbg(&led->udev->dev,
-                       "blue = %d, red = %d, green = %d, color = %.2x\n",
-                       led->blue, led->red, led->green, color);
-
-               retval = usb_control_msg(led->udev,
-                                       usb_sndctrlpipe(led->udev, 0),
-                                       0x12,
-                                       0xc8,
-                                       (0x02 * 0x100) + 0x0a,
-                                       (0x00 * 0x100) + color,
-                                       buffer,
-                                       8,
-                                       2000);
-               break;
-       }
-
-       case DREAM_CHEEKY_WEBMAIL_NOTIFIER:
-               dev_dbg(&led->udev->dev,
-                       "red = %d, green = %d, blue = %d\n",
-                       led->red, led->green, led->blue);
-
-               buffer[0] = led->red;
-               buffer[1] = led->green;
-               buffer[2] = led->blue;
-               buffer[3] = buffer[4] = buffer[5] = 0;
-               buffer[6] = 0x1a;
-               buffer[7] = 0x05;
-
-               retval = usb_control_msg(led->udev,
-                                       usb_sndctrlpipe(led->udev, 0),
-                                       0x09,
-                                       0x21,
-                                       0x200,
-                                       0,
-                                       buffer,
-                                       8,
-                                       2000);
-               break;
-
-       case RISO_KAGAKU_LED:
-               buffer[0] = RISO_KAGAKU_IX(led->red, led->green, led->blue);
-               buffer[1] = 0;
-               buffer[2] = 0;
-               buffer[3] = 0;
-               buffer[4] = 0;
-
-               retval = usb_interrupt_msg(led->udev,
-                       usb_sndctrlpipe(led->udev, 2),
-                       buffer, 5, &actlength, 1000 /*ms timeout*/);
-               break;
-
-       default:
-               dev_err(&led->udev->dev, "unknown device type %d\n", led->type);
-       }
-
-       if (retval)
-               dev_dbg(&led->udev->dev, "retval = %d\n", retval);
-       kfree(buffer);
-}
-
-#define show_set(value)        \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr,\
-                           char *buf)                                  \
-{                                                                      \
-       struct usb_interface *intf = to_usb_interface(dev);             \
-       struct usb_led *led = usb_get_intfdata(intf);                   \
-                                                                       \
-       return sprintf(buf, "%d\n", led->value);                        \
-}                                                                      \
-static ssize_t set_##value(struct device *dev, struct device_attribute *attr,\
-                          const char *buf, size_t count)               \
-{                                                                      \
-       struct usb_interface *intf = to_usb_interface(dev);             \
-       struct usb_led *led = usb_get_intfdata(intf);                   \
-       int temp = simple_strtoul(buf, NULL, 10);                       \
-                                                                       \
-       led->value = temp;                                              \
-       change_color(led);                                              \
-       return count;                                                   \
-}                                                                      \
-static DEVICE_ATTR(value, S_IRUGO | S_IWUSR, show_##value, set_##value);
-show_set(blue);
-show_set(red);
-show_set(green);
-
-static int led_probe(struct usb_interface *interface,
-                    const struct usb_device_id *id)
-{
-       struct usb_device *udev = interface_to_usbdev(interface);
-       struct usb_led *dev = NULL;
-       int retval = -ENOMEM;
-
-       dev = kzalloc(sizeof(struct usb_led), GFP_KERNEL);
-       if (dev == NULL) {
-               dev_err(&interface->dev, "out of memory\n");
-               goto error_mem;
-       }
-
-       dev->udev = usb_get_dev(udev);
-       dev->type = id->driver_info;
-
-       usb_set_intfdata(interface, dev);
-
-       retval = device_create_file(&interface->dev, &dev_attr_blue);
-       if (retval)
-               goto error;
-       retval = device_create_file(&interface->dev, &dev_attr_red);
-       if (retval)
-               goto error;
-       retval = device_create_file(&interface->dev, &dev_attr_green);
-       if (retval)
-               goto error;
-
-       if (dev->type == DREAM_CHEEKY_WEBMAIL_NOTIFIER) {
-               unsigned char *enable;
-
-               enable = kmemdup("\x1f\x02\0\x5f\0\0\x1a\x03", 8, GFP_KERNEL);
-               if (!enable) {
-                       dev_err(&interface->dev, "out of memory\n");
-                       retval = -ENOMEM;
-                       goto error;
-               }
-
-               retval = usb_control_msg(udev,
-                                       usb_sndctrlpipe(udev, 0),
-                                       0x09,
-                                       0x21,
-                                       0x200,
-                                       0,
-                                       enable,
-                                       8,
-                                       2000);
-
-               kfree(enable);
-               if (retval != 8)
-                       goto error;
-       }
-
-       dev_info(&interface->dev, "USB LED device now attached\n");
-       return 0;
-
-error:
-       device_remove_file(&interface->dev, &dev_attr_blue);
-       device_remove_file(&interface->dev, &dev_attr_red);
-       device_remove_file(&interface->dev, &dev_attr_green);
-       usb_set_intfdata(interface, NULL);
-       usb_put_dev(dev->udev);
-       kfree(dev);
-error_mem:
-       return retval;
-}
-
-static void led_disconnect(struct usb_interface *interface)
-{
-       struct usb_led *dev;
-
-       dev = usb_get_intfdata(interface);
-
-       device_remove_file(&interface->dev, &dev_attr_blue);
-       device_remove_file(&interface->dev, &dev_attr_red);
-       device_remove_file(&interface->dev, &dev_attr_green);
-
-       /* first remove the files, then set the pointer to NULL */
-       usb_set_intfdata(interface, NULL);
-
-       usb_put_dev(dev->udev);
-
-       kfree(dev);
-
-       dev_info(&interface->dev, "USB LED now disconnected\n");
-}
-
-static struct usb_driver led_driver = {
-       .name =         "usbled",
-       .probe =        led_probe,
-       .disconnect =   led_disconnect,
-       .id_table =     id_table,
-};
-
-module_usb_driver(led_driver);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
index 2b6787f..12700df 100644 (file)
 #include <linux/list.h>
 
 struct p9_fid *v9fs_fid_lookup(struct dentry *dentry);
+static inline struct p9_fid *v9fs_parent_fid(struct dentry *dentry)
+{
+       return v9fs_fid_lookup(dentry->d_parent);
+}
 struct p9_fid *v9fs_fid_clone(struct dentry *dentry);
 void v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid);
 struct p9_fid *v9fs_writeback_fid(struct dentry *dentry);
index c37fb9c..6181ad7 100644 (file)
@@ -231,7 +231,6 @@ static int v9fs_launder_page(struct page *page)
 /**
  * v9fs_direct_IO - 9P address space operation for direct I/O
  * @iocb: target I/O control block
- * @pos: offset in file to begin the operation
  *
  * The presence of v9fs_direct_IO() in the address space ops vector
  * allowes open() O_DIRECT flags which would have failed otherwise.
index e2e7c74..7da9a83 100644 (file)
@@ -595,7 +595,7 @@ static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags)
 
        v9ses = v9fs_inode2v9ses(dir);
        inode = d_inode(dentry);
-       dfid = v9fs_fid_lookup(dentry->d_parent);
+       dfid = v9fs_parent_fid(dentry);
        if (IS_ERR(dfid)) {
                retval = PTR_ERR(dfid);
                p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", retval);
@@ -653,7 +653,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
        ofid = NULL;
        fid = NULL;
        name = (char *) dentry->d_name.name;
-       dfid = v9fs_fid_lookup(dentry->d_parent);
+       dfid = v9fs_parent_fid(dentry);
        if (IS_ERR(dfid)) {
                err = PTR_ERR(dfid);
                p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
@@ -798,7 +798,7 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
 
        v9ses = v9fs_inode2v9ses(dir);
        /* We can walk d_parent because we hold the dir->i_mutex */
-       dfid = v9fs_fid_lookup(dentry->d_parent);
+       dfid = v9fs_parent_fid(dentry);
        if (IS_ERR(dfid))
                return ERR_CAST(dfid);
 
@@ -975,13 +975,13 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (IS_ERR(oldfid))
                return PTR_ERR(oldfid);
 
-       olddirfid = v9fs_fid_clone(old_dentry->d_parent);
+       olddirfid = v9fs_parent_fid(old_dentry);
        if (IS_ERR(olddirfid)) {
                retval = PTR_ERR(olddirfid);
                goto done;
        }
 
-       newdirfid = v9fs_fid_clone(new_dentry->d_parent);
+       newdirfid = v9fs_parent_fid(new_dentry);
        if (IS_ERR(newdirfid)) {
                retval = PTR_ERR(newdirfid);
                goto clunk_olddir;
index 1b51eaa..2ed04c2 100644 (file)
@@ -273,7 +273,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
        p9_debug(P9_DEBUG_VFS, "name:%s flags:0x%x mode:0x%hx\n",
                 name, flags, omode);
 
-       dfid = v9fs_fid_lookup(dentry->d_parent);
+       dfid = v9fs_parent_fid(dentry);
        if (IS_ERR(dfid)) {
                err = PTR_ERR(dfid);
                p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
@@ -389,7 +389,6 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
        umode_t mode;
        struct inode *inode;
        struct p9_qid qid;
-       struct dentry *dir_dentry;
        struct posix_acl *dacl = NULL, *pacl = NULL;
 
        p9_debug(P9_DEBUG_VFS, "name %pd\n", dentry);
@@ -400,8 +399,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
        if (dir->i_mode & S_ISGID)
                omode |= S_ISGID;
 
-       dir_dentry = dentry->d_parent;
-       dfid = v9fs_fid_lookup(dir_dentry);
+       dfid = v9fs_parent_fid(dentry);
        if (IS_ERR(dfid)) {
                err = PTR_ERR(dfid);
                p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
@@ -691,7 +689,7 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
        p9_debug(P9_DEBUG_VFS, "%lu,%s,%s\n", dir->i_ino, name, symname);
        v9ses = v9fs_inode2v9ses(dir);
 
-       dfid = v9fs_fid_lookup(dentry->d_parent);
+       dfid = v9fs_parent_fid(dentry);
        if (IS_ERR(dfid)) {
                err = PTR_ERR(dfid);
                p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
@@ -762,7 +760,6 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
                struct dentry *dentry)
 {
        int err;
-       struct dentry *dir_dentry;
        struct p9_fid *dfid, *oldfid;
        struct v9fs_session_info *v9ses;
 
@@ -770,8 +767,7 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
                 dir->i_ino, old_dentry, dentry);
 
        v9ses = v9fs_inode2v9ses(dir);
-       dir_dentry = dentry->d_parent;
-       dfid = v9fs_fid_lookup(dir_dentry);
+       dfid = v9fs_parent_fid(dentry);
        if (IS_ERR(dfid))
                return PTR_ERR(dfid);
 
@@ -822,7 +818,6 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
        struct p9_fid *fid = NULL, *dfid = NULL;
        struct inode *inode;
        struct p9_qid qid;
-       struct dentry *dir_dentry;
        struct posix_acl *dacl = NULL, *pacl = NULL;
 
        p9_debug(P9_DEBUG_VFS, " %lu,%pd mode: %hx MAJOR: %u MINOR: %u\n",
@@ -830,8 +825,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
                 MAJOR(rdev), MINOR(rdev));
 
        v9ses = v9fs_inode2v9ses(dir);
-       dir_dentry = dentry->d_parent;
-       dfid = v9fs_fid_lookup(dir_dentry);
+       dfid = v9fs_parent_fid(dentry);
        if (IS_ERR(dfid)) {
                err = PTR_ERR(dfid);
                p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
index fd4cf2c..bec25f7 100644 (file)
@@ -207,7 +207,7 @@ adfs_hash(const struct dentry *parent, struct qstr *qstr)
         */
        qstr->len = i = name_len;
        name = qstr->name;
-       hash = init_name_hash();
+       hash = init_name_hash(parent);
        while (i--) {
                char c;
 
index 00d3002..eb32029 100644 (file)
@@ -61,7 +61,7 @@ affs_get_toupper(struct super_block *sb)
  * Note: the dentry argument is the parent dentry.
  */
 static inline int
-__affs_hash_dentry(struct qstr *qstr, toupper_t toupper, bool notruncate)
+__affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr, toupper_t toupper, bool notruncate)
 {
        const u8 *name = qstr->name;
        unsigned long hash;
@@ -72,7 +72,7 @@ __affs_hash_dentry(struct qstr *qstr, toupper_t toupper, bool notruncate)
        if (retval)
                return retval;
 
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        len = min(qstr->len, AFFSNAMEMAX);
        for (; len > 0; name++, len--)
                hash = partial_name_hash(toupper(*name), hash);
@@ -84,7 +84,7 @@ __affs_hash_dentry(struct qstr *qstr, toupper_t toupper, bool notruncate)
 static int
 affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
 {
-       return __affs_hash_dentry(qstr, affs_toupper,
+       return __affs_hash_dentry(dentry, qstr, affs_toupper,
                                  affs_nofilenametruncate(dentry));
 
 }
@@ -92,7 +92,7 @@ affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
 static int
 affs_intl_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
 {
-       return __affs_hash_dentry(qstr, affs_intl_toupper,
+       return __affs_hash_dentry(dentry, qstr, affs_intl_toupper,
                                  affs_nofilenametruncate(dentry));
 
 }
index 631f155..7082144 100644 (file)
@@ -398,7 +398,7 @@ int autofs4_wait(struct autofs_sb_info *sbi,
                }
        }
        qstr.name = name;
-       qstr.hash = full_name_hash(name, qstr.len);
+       qstr.hash = full_name_hash(dentry, name, qstr.len);
 
        if (mutex_lock_interruptible(&sbi->wq_mutex)) {
                kfree(qstr.name);
index 3a3ced7..5417516 100644 (file)
@@ -637,13 +637,12 @@ static ssize_t bm_entry_write(struct file *file, const char __user *buffer,
                break;
        case 3:
                /* Delete this handler. */
-               root = dget(file->f_path.dentry->d_sb->s_root);
+               root = file_inode(file)->i_sb->s_root;
                inode_lock(d_inode(root));
 
                kill_node(e);
 
                inode_unlock(d_inode(root));
-               dput(root);
                break;
        default:
                return res;
@@ -665,8 +664,8 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
 {
        Node *e;
        struct inode *inode;
-       struct dentry *root, *dentry;
-       struct super_block *sb = file->f_path.dentry->d_sb;
+       struct super_block *sb = file_inode(file)->i_sb;
+       struct dentry *root = sb->s_root, *dentry;
        int err = 0;
 
        e = create_entry(buffer, count);
@@ -674,7 +673,6 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
        if (IS_ERR(e))
                return PTR_ERR(e);
 
-       root = dget(sb->s_root);
        inode_lock(d_inode(root));
        dentry = lookup_one_len(e->name, root, strlen(e->name));
        err = PTR_ERR(dentry);
@@ -712,7 +710,6 @@ out2:
        dput(dentry);
 out:
        inode_unlock(d_inode(root));
-       dput(root);
 
        if (err) {
                kfree(e);
@@ -753,14 +750,13 @@ static ssize_t bm_status_write(struct file *file, const char __user *buffer,
                break;
        case 3:
                /* Delete all handlers. */
-               root = dget(file->f_path.dentry->d_sb->s_root);
+               root = file_inode(file)->i_sb->s_root;
                inode_lock(d_inode(root));
 
                while (!list_empty(&entries))
                        kill_node(list_entry(entries.next, Node, list));
 
                inode_unlock(d_inode(root));
-               dput(root);
                break;
        default:
                return res;
index d012be4..5cbd539 100644 (file)
@@ -614,7 +614,6 @@ static void init_once(void *foo)
 
        memset(bdev, 0, sizeof(*bdev));
        mutex_init(&bdev->bd_mutex);
-       INIT_LIST_HEAD(&bdev->bd_inodes);
        INIT_LIST_HEAD(&bdev->bd_list);
 #ifdef CONFIG_SYSFS
        INIT_LIST_HEAD(&bdev->bd_holder_disks);
@@ -624,24 +623,13 @@ static void init_once(void *foo)
        mutex_init(&bdev->bd_fsfreeze_mutex);
 }
 
-static inline void __bd_forget(struct inode *inode)
-{
-       list_del_init(&inode->i_devices);
-       inode->i_bdev = NULL;
-       inode->i_mapping = &inode->i_data;
-}
-
 static void bdev_evict_inode(struct inode *inode)
 {
        struct block_device *bdev = &BDEV_I(inode)->bdev;
-       struct list_head *p;
        truncate_inode_pages_final(&inode->i_data);
        invalidate_inode_buffers(inode); /* is it needed here? */
        clear_inode(inode);
        spin_lock(&bdev_lock);
-       while ( (p = bdev->bd_inodes.next) != &bdev->bd_inodes ) {
-               __bd_forget(list_entry(p, struct inode, i_devices));
-       }
        list_del_init(&bdev->bd_list);
        spin_unlock(&bdev_lock);
 }
@@ -805,7 +793,6 @@ static struct block_device *bd_acquire(struct inode *inode)
                        bdgrab(bdev);
                        inode->i_bdev = bdev;
                        inode->i_mapping = bdev->bd_inode->i_mapping;
-                       list_add(&inode->i_devices, &bdev->bd_inodes);
                }
                spin_unlock(&bdev_lock);
        }
@@ -821,7 +808,8 @@ void bd_forget(struct inode *inode)
        spin_lock(&bdev_lock);
        if (!sb_is_blkdev_sb(inode->i_sb))
                bdev = inode->i_bdev;
-       __bd_forget(inode);
+       inode->i_bdev = NULL;
+       inode->i_mapping = &inode->i_data;
        spin_unlock(&bdev_lock);
 
        if (bdev)
index eccd339..125b90f 100644 (file)
@@ -93,7 +93,6 @@ static int cachefiles_histogram_open(struct inode *inode, struct file *file)
 }
 
 static const struct file_operations cachefiles_histogram_fops = {
-       .owner          = THIS_MODULE,
        .open           = cachefiles_histogram_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index f059b59..99bdef6 100644 (file)
@@ -1164,7 +1164,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
 
                        dname.name = rinfo->dname;
                        dname.len = rinfo->dname_len;
-                       dname.hash = full_name_hash(dname.name, dname.len);
+                       dname.hash = full_name_hash(parent, dname.name, dname.len);
                        vino.ino = le64_to_cpu(rinfo->targeti.in->ino);
                        vino.snap = le64_to_cpu(rinfo->targeti.in->snapid);
 retry_lookup:
@@ -1508,7 +1508,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
 
                dname.name = rde->name;
                dname.len = rde->name_len;
-               dname.hash = full_name_hash(dname.name, dname.len);
+               dname.hash = full_name_hash(parent, dname.name, dname.len);
 
                vino.ino = le64_to_cpu(rde->inode.in->ino);
                vino.snap = le64_to_cpu(rde->inode.in->snapid);
index 2103b82..4e8678a 100644 (file)
@@ -3204,7 +3204,7 @@ static void handle_lease(struct ceph_mds_client *mdsc,
                WARN_ON(1);
                goto release;  /* hrm... */
        }
-       dname.hash = full_name_hash(dname.name, dname.len);
+       dname.hash = full_name_hash(parent, dname.name, dname.len);
        dentry = d_lookup(parent, &dname);
        dput(parent);
        if (!dentry)
index 788e191..6c58e13 100644 (file)
@@ -244,7 +244,6 @@ static int cifs_debug_data_proc_open(struct inode *inode, struct file *file)
 }
 
 static const struct file_operations cifs_debug_data_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = cifs_debug_data_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
@@ -361,7 +360,6 @@ static int cifs_stats_proc_open(struct inode *inode, struct file *file)
 }
 
 static const struct file_operations cifs_stats_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = cifs_stats_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
@@ -447,7 +445,6 @@ static ssize_t cifsFYI_proc_write(struct file *file, const char __user *buffer,
 }
 
 static const struct file_operations cifsFYI_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = cifsFYI_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
@@ -479,7 +476,6 @@ static ssize_t cifs_linux_ext_proc_write(struct file *file,
 }
 
 static const struct file_operations cifs_linux_ext_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = cifs_linux_ext_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
@@ -511,7 +507,6 @@ static ssize_t cifs_lookup_cache_proc_write(struct file *file,
 }
 
 static const struct file_operations cifs_lookup_cache_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = cifs_lookup_cache_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
@@ -543,7 +538,6 @@ static ssize_t traceSMB_proc_write(struct file *file, const char __user *buffer,
 }
 
 static const struct file_operations traceSMB_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = traceSMB_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
@@ -655,7 +649,6 @@ static ssize_t cifs_security_flags_proc_write(struct file *file,
 }
 
 static const struct file_operations cifs_security_flags_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = cifs_security_flags_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index fb0903f..5efd6f1 100644 (file)
@@ -856,7 +856,7 @@ static int cifs_ci_hash(const struct dentry *dentry, struct qstr *q)
        wchar_t c;
        int i, charlen;
 
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        for (i = 0; i < q->len; i += charlen) {
                charlen = codepage->char2uni(&q->name[i], q->len - i, &c);
                /* error out if we can't convert the character */
index f36a404..b0b9cda 100644 (file)
@@ -35,7 +35,6 @@ const struct inode_operations coda_ioctl_inode_operations = {
 };
 
 const struct file_operations coda_ioctl_operations = {
-       .owner          = THIS_MODULE,
        .unlocked_ioctl = coda_pioctl,
        .llseek         = noop_llseek,
 };
index 432b9e6..993dc6f 100644 (file)
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -75,13 +75,13 @@ static long dax_map_atomic(struct block_device *bdev, struct blk_dax_ctl *dax)
        struct request_queue *q = bdev->bd_queue;
        long rc = -EIO;
 
-       dax->addr = (void __pmem *) ERR_PTR(-EIO);
+       dax->addr = ERR_PTR(-EIO);
        if (blk_queue_enter(q, true) != 0)
                return rc;
 
        rc = bdev_direct_access(bdev, dax);
        if (rc < 0) {
-               dax->addr = (void __pmem *) ERR_PTR(rc);
+               dax->addr = ERR_PTR(rc);
                blk_queue_exit(q);
                return rc;
        }
@@ -147,12 +147,12 @@ static ssize_t dax_io(struct inode *inode, struct iov_iter *iter,
                      struct buffer_head *bh)
 {
        loff_t pos = start, max = start, bh_max = start;
-       bool hole = false, need_wmb = false;
+       bool hole = false;
        struct block_device *bdev = NULL;
        int rw = iov_iter_rw(iter), rc;
        long map_len = 0;
        struct blk_dax_ctl dax = {
-               .addr = (void __pmem *) ERR_PTR(-EIO),
+               .addr = ERR_PTR(-EIO),
        };
        unsigned blkbits = inode->i_blkbits;
        sector_t file_blks = (i_size_read(inode) + (1 << blkbits) - 1)
@@ -218,7 +218,6 @@ static ssize_t dax_io(struct inode *inode, struct iov_iter *iter,
 
                if (iov_iter_rw(iter) == WRITE) {
                        len = copy_from_iter_pmem(dax.addr, max - pos, iter);
-                       need_wmb = true;
                } else if (!hole)
                        len = copy_to_iter((void __force *) dax.addr, max - pos,
                                        iter);
@@ -235,8 +234,6 @@ static ssize_t dax_io(struct inode *inode, struct iov_iter *iter,
                        dax.addr += len;
        }
 
-       if (need_wmb)
-               wmb_pmem();
        dax_unmap_atomic(bdev, &dax);
 
        return (pos == start) ? rc : pos - start;
@@ -788,7 +785,6 @@ int dax_writeback_mapping_range(struct address_space *mapping,
                                return ret;
                }
        }
-       wmb_pmem();
        return 0;
 }
 EXPORT_SYMBOL_GPL(dax_writeback_mapping_range);
@@ -1187,7 +1183,6 @@ int __dax_zero_page_range(struct block_device *bdev, sector_t sector,
                if (dax_map_atomic(bdev, &dax) < 0)
                        return PTR_ERR(dax.addr);
                clear_pmem(dax.addr + offset, length);
-               wmb_pmem();
                dax_unmap_atomic(bdev, &dax);
        }
        return 0;
index d6847d7..b90cf8e 100644 (file)
@@ -104,11 +104,9 @@ static unsigned int d_hash_shift __read_mostly;
 
 static struct hlist_bl_head *dentry_hashtable __read_mostly;
 
-static inline struct hlist_bl_head *d_hash(const struct dentry *parent,
-                                       unsigned int hash)
+static inline struct hlist_bl_head *d_hash(unsigned int hash)
 {
-       hash += (unsigned long) parent / L1_CACHE_BYTES;
-       return dentry_hashtable + hash_32(hash, d_hash_shift);
+       return dentry_hashtable + (hash >> (32 - d_hash_shift));
 }
 
 #define IN_LOOKUP_SHIFT 10
@@ -226,10 +224,9 @@ static inline int dentry_string_cmp(const unsigned char *cs, const unsigned char
 
 static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *ct, unsigned tcount)
 {
-       const unsigned char *cs;
        /*
         * Be careful about RCU walk racing with rename:
-        * use ACCESS_ONCE to fetch the name pointer.
+        * use 'lockless_dereference' to fetch the name pointer.
         *
         * NOTE! Even if a rename will mean that the length
         * was not loaded atomically, we don't care. The
@@ -243,8 +240,8 @@ static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *c
         * early because the data cannot match (there can
         * be no NUL in the ct/tcount data)
         */
-       cs = ACCESS_ONCE(dentry->d_name.name);
-       smp_read_barrier_depends();
+       const unsigned char *cs = lockless_dereference(dentry->d_name.name);
+
        return dentry_string_cmp(cs, ct, tcount);
 }
 
@@ -335,44 +332,21 @@ static inline void dentry_rcuwalk_invalidate(struct dentry *dentry)
 
 /*
  * Release the dentry's inode, using the filesystem
- * d_iput() operation if defined. Dentry has no refcount
- * and is unhashed.
- */
-static void dentry_iput(struct dentry * dentry)
-       __releases(dentry->d_lock)
-       __releases(dentry->d_inode->i_lock)
-{
-       struct inode *inode = dentry->d_inode;
-       if (inode) {
-               __d_clear_type_and_inode(dentry);
-               hlist_del_init(&dentry->d_u.d_alias);
-               spin_unlock(&dentry->d_lock);
-               spin_unlock(&inode->i_lock);
-               if (!inode->i_nlink)
-                       fsnotify_inoderemove(inode);
-               if (dentry->d_op && dentry->d_op->d_iput)
-                       dentry->d_op->d_iput(dentry, inode);
-               else
-                       iput(inode);
-       } else {
-               spin_unlock(&dentry->d_lock);
-       }
-}
-
-/*
- * Release the dentry's inode, using the filesystem
- * d_iput() operation if defined. dentry remains in-use.
+ * d_iput() operation if defined.
  */
 static void dentry_unlink_inode(struct dentry * dentry)
        __releases(dentry->d_lock)
        __releases(dentry->d_inode->i_lock)
 {
        struct inode *inode = dentry->d_inode;
+       bool hashed = !d_unhashed(dentry);
 
-       raw_write_seqcount_begin(&dentry->d_seq);
+       if (hashed)
+               raw_write_seqcount_begin(&dentry->d_seq);
        __d_clear_type_and_inode(dentry);
        hlist_del_init(&dentry->d_u.d_alias);
-       raw_write_seqcount_end(&dentry->d_seq);
+       if (hashed)
+               raw_write_seqcount_end(&dentry->d_seq);
        spin_unlock(&dentry->d_lock);
        spin_unlock(&inode->i_lock);
        if (!inode->i_nlink)
@@ -488,7 +462,7 @@ void __d_drop(struct dentry *dentry)
                if (unlikely(IS_ROOT(dentry)))
                        b = &dentry->d_sb->s_anon;
                else
-                       b = d_hash(dentry->d_parent, dentry->d_name.hash);
+                       b = d_hash(dentry->d_name.hash);
 
                hlist_bl_lock(b);
                __hlist_bl_del(&dentry->d_hash);
@@ -573,12 +547,10 @@ static void __dentry_kill(struct dentry *dentry)
        dentry_unlist(dentry, parent);
        if (parent)
                spin_unlock(&parent->d_lock);
-       dentry_iput(dentry);
-       /*
-        * dentry_iput drops the locks, at which point nobody (except
-        * transient RCU lookups) can reach this dentry.
-        */
-       BUG_ON(dentry->d_lockref.count > 0);
+       if (dentry->d_inode)
+               dentry_unlink_inode(dentry);
+       else
+               spin_unlock(&dentry->d_lock);
        this_cpu_dec(nr_dentry);
        if (dentry->d_op && dentry->d_op->d_release)
                dentry->d_op->d_release(dentry);
@@ -622,7 +594,6 @@ static struct dentry *dentry_kill(struct dentry *dentry)
 
 failed:
        spin_unlock(&dentry->d_lock);
-       cpu_relax();
        return dentry; /* try again with same dentry */
 }
 
@@ -796,6 +767,8 @@ void dput(struct dentry *dentry)
                return;
 
 repeat:
+       might_sleep();
+
        rcu_read_lock();
        if (likely(fast_dput(dentry))) {
                rcu_read_unlock();
@@ -829,8 +802,10 @@ repeat:
 
 kill_it:
        dentry = dentry_kill(dentry);
-       if (dentry)
+       if (dentry) {
+               cond_resched();
                goto repeat;
+       }
 }
 EXPORT_SYMBOL(dput);
 
@@ -1595,6 +1570,7 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
 {
        struct dentry *dentry;
        char *dname;
+       int err;
 
        dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL);
        if (!dentry)
@@ -1653,6 +1629,16 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
        INIT_LIST_HEAD(&dentry->d_child);
        d_set_d_op(dentry, dentry->d_sb->s_d_op);
 
+       if (dentry->d_op && dentry->d_op->d_init) {
+               err = dentry->d_op->d_init(dentry);
+               if (err) {
+                       if (dname_external(dentry))
+                               kfree(external_name(dentry));
+                       kmem_cache_free(dentry_cache, dentry);
+                       return NULL;
+               }
+       }
+
        this_cpu_inc(nr_dentry);
 
        return dentry;
@@ -1716,7 +1702,7 @@ struct dentry *d_alloc_name(struct dentry *parent, const char *name)
        struct qstr q;
 
        q.name = name;
-       q.hash_len = hashlen_string(name);
+       q.hash_len = hashlen_string(parent, name);
        return d_alloc(parent, &q);
 }
 EXPORT_SYMBOL(d_alloc_name);
@@ -1729,7 +1715,6 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
                                DCACHE_OP_REVALIDATE    |
                                DCACHE_OP_WEAK_REVALIDATE       |
                                DCACHE_OP_DELETE        |
-                               DCACHE_OP_SELECT_INODE  |
                                DCACHE_OP_REAL));
        dentry->d_op = op;
        if (!op)
@@ -1746,8 +1731,6 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
                dentry->d_flags |= DCACHE_OP_DELETE;
        if (op->d_prune)
                dentry->d_flags |= DCACHE_OP_PRUNE;
-       if (op->d_select_inode)
-               dentry->d_flags |= DCACHE_OP_SELECT_INODE;
        if (op->d_real)
                dentry->d_flags |= DCACHE_OP_REAL;
 
@@ -1815,7 +1798,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
        raw_write_seqcount_begin(&dentry->d_seq);
        __d_set_inode_and_type(dentry, inode, add_flags);
        raw_write_seqcount_end(&dentry->d_seq);
-       __fsnotify_d_instantiate(dentry);
+       fsnotify_update_flags(dentry);
        spin_unlock(&dentry->d_lock);
 }
 
@@ -2067,42 +2050,19 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,
 }
 EXPORT_SYMBOL(d_add_ci);
 
-/*
- * Do the slow-case of the dentry name compare.
- *
- * Unlike the dentry_cmp() function, we need to atomically
- * load the name and length information, so that the
- * filesystem can rely on them, and can use the 'name' and
- * 'len' information without worrying about walking off the
- * end of memory etc.
- *
- * Thus the read_seqcount_retry() and the "duplicate" info
- * in arguments (the low-level filesystem should not look
- * at the dentry inode or name contents directly, since
- * rename can change them while we're in RCU mode).
- */
-enum slow_d_compare {
-       D_COMP_OK,
-       D_COMP_NOMATCH,
-       D_COMP_SEQRETRY,
-};
 
-static noinline enum slow_d_compare slow_dentry_cmp(
-               const struct dentry *parent,
-               struct dentry *dentry,
-               unsigned int seq,
-               const struct qstr *name)
+static inline bool d_same_name(const struct dentry *dentry,
+                               const struct dentry *parent,
+                               const struct qstr *name)
 {
-       int tlen = dentry->d_name.len;
-       const char *tname = dentry->d_name.name;
-
-       if (read_seqcount_retry(&dentry->d_seq, seq)) {
-               cpu_relax();
-               return D_COMP_SEQRETRY;
+       if (likely(!(parent->d_flags & DCACHE_OP_COMPARE))) {
+               if (dentry->d_name.len != name->len)
+                       return false;
+               return dentry_cmp(dentry, name->name, name->len) == 0;
        }
-       if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
-               return D_COMP_NOMATCH;
-       return D_COMP_OK;
+       return parent->d_op->d_compare(parent, dentry,
+                                      dentry->d_name.len, dentry->d_name.name,
+                                      name) == 0;
 }
 
 /**
@@ -2140,7 +2100,7 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent,
 {
        u64 hashlen = name->hash_len;
        const unsigned char *str = name->name;
-       struct hlist_bl_head *b = d_hash(parent, hashlen_hash(hashlen));
+       struct hlist_bl_head *b = d_hash(hashlen_hash(hashlen));
        struct hlist_bl_node *node;
        struct dentry *dentry;
 
@@ -2181,6 +2141,9 @@ seqretry:
                 * dentry compare, we will do seqretries until it is stable,
                 * and if we end up with a successful lookup, we actually
                 * want to exit RCU lookup anyway.
+                *
+                * Note that raw_seqcount_begin still *does* smp_rmb(), so
+                * we are still guaranteed NUL-termination of ->d_name.name.
                 */
                seq = raw_seqcount_begin(&dentry->d_seq);
                if (dentry->d_parent != parent)
@@ -2189,24 +2152,28 @@ seqretry:
                        continue;
 
                if (unlikely(parent->d_flags & DCACHE_OP_COMPARE)) {
+                       int tlen;
+                       const char *tname;
                        if (dentry->d_name.hash != hashlen_hash(hashlen))
                                continue;
-                       *seqp = seq;
-                       switch (slow_dentry_cmp(parent, dentry, seq, name)) {
-                       case D_COMP_OK:
-                               return dentry;
-                       case D_COMP_NOMATCH:
-                               continue;
-                       default:
+                       tlen = dentry->d_name.len;
+                       tname = dentry->d_name.name;
+                       /* we want a consistent (name,len) pair */
+                       if (read_seqcount_retry(&dentry->d_seq, seq)) {
+                               cpu_relax();
                                goto seqretry;
                        }
+                       if (parent->d_op->d_compare(parent, dentry,
+                                                   tlen, tname, name) != 0)
+                               continue;
+               } else {
+                       if (dentry->d_name.hash_len != hashlen)
+                               continue;
+                       if (dentry_cmp(dentry, str, hashlen_len(hashlen)) != 0)
+                               continue;
                }
-
-               if (dentry->d_name.hash_len != hashlen)
-                       continue;
                *seqp = seq;
-               if (!dentry_cmp(dentry, str, hashlen_len(hashlen)))
-                       return dentry;
+               return dentry;
        }
        return NULL;
 }
@@ -2254,10 +2221,8 @@ EXPORT_SYMBOL(d_lookup);
  */
 struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name)
 {
-       unsigned int len = name->len;
        unsigned int hash = name->hash;
-       const unsigned char *str = name->name;
-       struct hlist_bl_head *b = d_hash(parent, hash);
+       struct hlist_bl_head *b = d_hash(hash);
        struct hlist_bl_node *node;
        struct dentry *found = NULL;
        struct dentry *dentry;
@@ -2295,21 +2260,8 @@ struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name)
                if (d_unhashed(dentry))
                        goto next;
 
-               /*
-                * It is safe to compare names since d_move() cannot
-                * change the qstr (protected by d_lock).
-                */
-               if (parent->d_flags & DCACHE_OP_COMPARE) {
-                       int tlen = dentry->d_name.len;
-                       const char *tname = dentry->d_name.name;
-                       if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
-                               goto next;
-               } else {
-                       if (dentry->d_name.len != len)
-                               goto next;
-                       if (dentry_cmp(dentry, str, len))
-                               goto next;
-               }
+               if (!d_same_name(dentry, parent, name))
+                       goto next;
 
                dentry->d_lockref.count++;
                found = dentry;
@@ -2337,7 +2289,7 @@ struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name)
         * calculate the standard hash first, as the d_op->d_hash()
         * routine may choose to leave the hash value unchanged.
         */
-       name->hash = full_name_hash(name->name, name->len);
+       name->hash = full_name_hash(dir, name->name, name->len);
        if (dir->d_flags & DCACHE_OP_HASH) {
                int err = dir->d_op->d_hash(dir, name);
                if (unlikely(err < 0))
@@ -2410,7 +2362,7 @@ static void __d_rehash(struct dentry * entry, struct hlist_bl_head *b)
 
 static void _d_rehash(struct dentry * entry)
 {
-       __d_rehash(entry, d_hash(entry->d_parent, entry->d_name.hash));
+       __d_rehash(entry, d_hash(entry->d_name.hash));
 }
 
 /**
@@ -2462,9 +2414,7 @@ struct dentry *d_alloc_parallel(struct dentry *parent,
                                const struct qstr *name,
                                wait_queue_head_t *wq)
 {
-       unsigned int len = name->len;
        unsigned int hash = name->hash;
-       const unsigned char *str = name->name;
        struct hlist_bl_head *b = in_lookup_hash(parent, hash);
        struct hlist_bl_node *node;
        struct dentry *new = d_alloc(parent, name);
@@ -2515,17 +2465,8 @@ retry:
                        continue;
                if (dentry->d_parent != parent)
                        continue;
-               if (parent->d_flags & DCACHE_OP_COMPARE) {
-                       int tlen = dentry->d_name.len;
-                       const char *tname = dentry->d_name.name;
-                       if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
-                               continue;
-               } else {
-                       if (dentry->d_name.len != len)
-                               continue;
-                       if (dentry_cmp(dentry, str, len))
-                               continue;
-               }
+               if (!d_same_name(dentry, parent, name))
+                       continue;
                hlist_bl_unlock(b);
                /* now we can try to grab a reference */
                if (!lockref_get_not_dead(&dentry->d_lockref)) {
@@ -2552,17 +2493,8 @@ retry:
                        goto mismatch;
                if (unlikely(d_unhashed(dentry)))
                        goto mismatch;
-               if (parent->d_flags & DCACHE_OP_COMPARE) {
-                       int tlen = dentry->d_name.len;
-                       const char *tname = dentry->d_name.name;
-                       if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
-                               goto mismatch;
-               } else {
-                       if (unlikely(dentry->d_name.len != len))
-                               goto mismatch;
-                       if (unlikely(dentry_cmp(dentry, str, len)))
-                               goto mismatch;
-               }
+               if (unlikely(!d_same_name(dentry, parent, name)))
+                       goto mismatch;
                /* OK, it *is* a hashed match; return it */
                spin_unlock(&dentry->d_lock);
                dput(new);
@@ -2615,7 +2547,7 @@ static inline void __d_add(struct dentry *dentry, struct inode *inode)
                raw_write_seqcount_begin(&dentry->d_seq);
                __d_set_inode_and_type(dentry, inode, add_flags);
                raw_write_seqcount_end(&dentry->d_seq);
-               __fsnotify_d_instantiate(dentry);
+               fsnotify_update_flags(dentry);
        }
        _d_rehash(dentry);
        if (dir)
@@ -2658,8 +2590,6 @@ EXPORT_SYMBOL(d_add);
 struct dentry *d_exact_alias(struct dentry *entry, struct inode *inode)
 {
        struct dentry *alias;
-       int len = entry->d_name.len;
-       const char *name = entry->d_name.name;
        unsigned int hash = entry->d_name.hash;
 
        spin_lock(&inode->i_lock);
@@ -2673,9 +2603,7 @@ struct dentry *d_exact_alias(struct dentry *entry, struct inode *inode)
                        continue;
                if (alias->d_parent != entry->d_parent)
                        continue;
-               if (alias->d_name.len != len)
-                       continue;
-               if (dentry_cmp(alias, name, len))
+               if (!d_same_name(alias, entry->d_parent, &entry->d_name))
                        continue;
                spin_lock(&alias->d_lock);
                if (!d_unhashed(alias)) {
@@ -2874,7 +2802,7 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
         * for the same hash queue because of how unlikely it is.
         */
        __d_drop(dentry);
-       __d_rehash(dentry, d_hash(target->d_parent, target->d_name.hash));
+       __d_rehash(dentry, d_hash(target->d_name.hash));
 
        /*
         * Unhash the target (d_delete() is not usable here).  If exchanging
@@ -2882,8 +2810,7 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
         */
        __d_drop(target);
        if (exchange) {
-               __d_rehash(target,
-                          d_hash(dentry->d_parent, dentry->d_name.hash));
+               __d_rehash(target, d_hash(dentry->d_name.hash));
        }
 
        /* Switch the names.. */
@@ -2906,8 +2833,8 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
                list_move(&target->d_child, &target->d_parent->d_subdirs);
                list_move(&dentry->d_child, &dentry->d_parent->d_subdirs);
                if (exchange)
-                       fsnotify_d_move(target);
-               fsnotify_d_move(dentry);
+                       fsnotify_update_flags(target);
+               fsnotify_update_flags(dentry);
        }
 
        write_seqcount_end(&target->d_seq);
index 4bc1f68..72361ba 100644 (file)
@@ -621,9 +621,6 @@ void debugfs_remove(struct dentry *dentry)
                return;
 
        parent = dentry->d_parent;
-       if (!parent || d_really_is_negative(parent))
-               return;
-
        inode_lock(d_inode(parent));
        ret = __debugfs_remove(dentry, parent);
        inode_unlock(d_inode(parent));
@@ -654,10 +651,6 @@ void debugfs_remove_recursive(struct dentry *dentry)
        if (IS_ERR_OR_NULL(dentry))
                return;
 
-       parent = dentry->d_parent;
-       if (!parent || d_really_is_negative(parent))
-               return;
-
        parent = dentry;
  down:
        inode_lock(d_inode(parent));
index 9cb54a3..a5e607e 100644 (file)
@@ -65,7 +65,7 @@ static int efivarfs_d_compare(const struct dentry *parent,
 
 static int efivarfs_d_hash(const struct dentry *dentry, struct qstr *qstr)
 {
-       unsigned long hash = init_name_hash();
+       unsigned long hash = init_name_hash(dentry);
        const unsigned char *s = qstr->name;
        unsigned int len = qstr->len;
 
@@ -98,7 +98,7 @@ static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)
        q.name = name;
        q.len = strlen(name);
 
-       err = efivarfs_d_hash(NULL, &q);
+       err = efivarfs_d_hash(parent, &q);
        if (err)
                return ERR_PTR(err);
 
index 1156216..f418f55 100644 (file)
@@ -2350,7 +2350,6 @@ static int ext4_mb_seq_groups_open(struct inode *inode, struct file *file)
 }
 
 const struct file_operations ext4_seq_mb_groups_fops = {
-       .owner          = THIS_MODULE,
        .open           = ext4_mb_seq_groups_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index 1420a3c..73bcfd4 100644 (file)
@@ -359,7 +359,6 @@ static int name##_open(struct inode *inode, struct file *file) \
 } \
 \
 static const struct file_operations ext4_seq_##name##_fops = { \
-       .owner          = THIS_MODULE, \
        .open           = name##_open, \
        .read           = seq_read, \
        .llseek         = seq_lseek, \
index b97c065..1b86d3f 100644 (file)
@@ -961,7 +961,6 @@ static int _name##_open_fs(struct inode *inode, struct file *file)  \
 }                                                                      \
                                                                        \
 static const struct file_operations f2fs_seq_##_name##_fops = {                \
-       .owner = THIS_MODULE,                                           \
        .open = _name##_open_fs,                                        \
        .read = seq_read,                                               \
        .llseek = seq_lseek,                                            \
index 3bcf579..da04c02 100644 (file)
@@ -1589,7 +1589,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
 
        /*
         * GFP_KERNEL is ok here, because while we do hold the
-        * supeblock lock, memory pressure can't call back into
+        * superblock lock, memory pressure can't call back into
         * the filesystem, since we're only just about to mount
         * it and have no inodes etc active!
         */
@@ -1726,7 +1726,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
        sbi->dir_entries = bpb.fat_dir_entries;
        if (sbi->dir_entries & (sbi->dir_per_block - 1)) {
                if (!silent)
-                       fat_msg(sb, KERN_ERR, "bogus directory-entries per block"
+                       fat_msg(sb, KERN_ERR, "bogus number of directory entries"
                               " (%u)", sbi->dir_entries);
                goto out_invalid;
        }
index b7e2b33..1337c0c 100644 (file)
@@ -154,7 +154,7 @@ static int msdos_hash(const struct dentry *dentry, struct qstr *qstr)
 
        error = msdos_format_name(qstr->name, qstr->len, msdos_name, options);
        if (!error)
-               qstr->hash = full_name_hash(msdos_name, MSDOS_NAME);
+               qstr->hash = full_name_hash(dentry, msdos_name, MSDOS_NAME);
        return 0;
 }
 
index 7092584..6ccdf3f 100644 (file)
@@ -107,7 +107,7 @@ static unsigned int vfat_striptail_len(const struct qstr *qstr)
  */
 static int vfat_hash(const struct dentry *dentry, struct qstr *qstr)
 {
-       qstr->hash = full_name_hash(qstr->name, vfat_striptail_len(qstr));
+       qstr->hash = full_name_hash(dentry, qstr->name, vfat_striptail_len(qstr));
        return 0;
 }
 
@@ -127,7 +127,7 @@ static int vfat_hashi(const struct dentry *dentry, struct qstr *qstr)
        name = qstr->name;
        len = vfat_striptail_len(qstr);
 
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        while (len--)
                hash = partial_name_hash(nls_tolower(t, *name++), hash);
        qstr->hash = end_name_hash(hash);
index 6f9c9f6..56c8fda 100644 (file)
@@ -1807,8 +1807,8 @@ static struct wb_writeback_work *get_next_work_item(struct bdi_writeback *wb)
  */
 static unsigned long get_nr_dirty_pages(void)
 {
-       return global_page_state(NR_FILE_DIRTY) +
-               global_page_state(NR_UNSTABLE_NFS) +
+       return global_node_page_state(NR_FILE_DIRTY) +
+               global_node_page_state(NR_UNSTABLE_NFS) +
                get_nr_dirty_inodes();
 }
 
index 7d637e2..15a3d04 100644 (file)
@@ -99,7 +99,6 @@ static int fscache_histogram_open(struct inode *inode, struct file *file)
 }
 
 const struct file_operations fscache_histogram_fops = {
-       .owner          = THIS_MODULE,
        .open           = fscache_histogram_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index 6b028b7..5d5ddaa 100644 (file)
@@ -404,7 +404,6 @@ static int fscache_objlist_release(struct inode *inode, struct file *file)
 }
 
 const struct file_operations fscache_objlist_fops = {
-       .owner          = THIS_MODULE,
        .open           = fscache_objlist_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index 7cfa0aa..7ac6e83 100644 (file)
@@ -295,7 +295,6 @@ static int fscache_stats_open(struct inode *inode, struct file *file)
 }
 
 const struct file_operations fscache_stats_fops = {
-       .owner          = THIS_MODULE,
        .open           = fscache_stats_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index cbece12..203adf3 100644 (file)
@@ -1525,7 +1525,6 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size,
                goto err;
        fuse_copy_finish(cs);
        buf[outarg.namelen] = 0;
-       name.hash = full_name_hash(name.name, name.len);
 
        down_read(&fc->killsb);
        err = -ENOENT;
@@ -1576,7 +1575,6 @@ static int fuse_notify_delete(struct fuse_conn *fc, unsigned int size,
                goto err;
        fuse_copy_finish(cs);
        buf[outarg.namelen] = 0;
-       name.hash = full_name_hash(name.name, name.len);
 
        down_read(&fc->killsb);
        err = -ENOENT;
index cca7b04..5f16277 100644 (file)
@@ -955,6 +955,7 @@ int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
        if (!dir)
                goto unlock;
 
+       name->hash = full_name_hash(dir, name->name, name->len);
        entry = d_lookup(dir, name);
        dput(dir);
        if (!entry)
@@ -1204,7 +1205,7 @@ static int fuse_direntplus_link(struct file *file,
 
        fc = get_fuse_conn(dir);
 
-       name.hash = full_name_hash(name.name, name.len);
+       name.hash = full_name_hash(parent, name.name, name.len);
        dentry = d_lookup(parent, &name);
        if (!dentry) {
 retry:
index 9154f86..2382f22 100644 (file)
@@ -1452,7 +1452,7 @@ static void fuse_writepage_finish(struct fuse_conn *fc, struct fuse_req *req)
        list_del(&req->writepages_entry);
        for (i = 0; i < req->num_pages; i++) {
                dec_wb_stat(&bdi->wb, WB_WRITEBACK);
-               dec_zone_page_state(req->pages[i], NR_WRITEBACK_TEMP);
+               dec_node_page_state(req->pages[i], NR_WRITEBACK_TEMP);
                wb_writeout_inc(&bdi->wb);
        }
        wake_up(&fi->page_waitq);
@@ -1642,7 +1642,7 @@ static int fuse_writepage_locked(struct page *page)
        req->inode = inode;
 
        inc_wb_stat(&inode_to_bdi(inode)->wb, WB_WRITEBACK);
-       inc_zone_page_state(tmp_page, NR_WRITEBACK_TEMP);
+       inc_node_page_state(tmp_page, NR_WRITEBACK_TEMP);
 
        spin_lock(&fc->lock);
        list_add(&req->writepages_entry, &fi->writepages);
@@ -1756,7 +1756,7 @@ static bool fuse_writepage_in_flight(struct fuse_req *new_req,
                spin_unlock(&fc->lock);
 
                dec_wb_stat(&bdi->wb, WB_WRITEBACK);
-               dec_zone_page_state(page, NR_WRITEBACK_TEMP);
+               dec_node_page_state(page, NR_WRITEBACK_TEMP);
                wb_writeout_inc(&bdi->wb);
                fuse_writepage_free(fc, new_req);
                fuse_request_free(new_req);
@@ -1855,7 +1855,7 @@ static int fuse_writepages_fill(struct page *page,
        req->page_descs[req->num_pages].length = PAGE_SIZE;
 
        inc_wb_stat(&inode_to_bdi(inode)->wb, WB_WRITEBACK);
-       inc_zone_page_state(tmp_page, NR_WRITEBACK_TEMP);
+       inc_node_page_state(tmp_page, NR_WRITEBACK_TEMP);
 
        err = 0;
        if (is_writeback && fuse_writepage_in_flight(req, page)) {
index 8eed66a..02a3845 100644 (file)
@@ -128,7 +128,7 @@ static ssize_t hfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
 {
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
-       struct inode *inode = file_inode(file)->i_mapping->host;
+       struct inode *inode = mapping->host;
        size_t count = iov_iter_count(iter);
        ssize_t ret;
 
index 85b610c..ec9f164 100644 (file)
@@ -59,7 +59,7 @@ int hfs_hash_dentry(const struct dentry *dentry, struct qstr *this)
        if (len > HFS_NAMELEN)
                len = HFS_NAMELEN;
 
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        for (; len; len--)
                hash = partial_name_hash(caseorder[*name++], hash);
        this->hash = end_name_hash(hash);
index ef9fefe..19462d7 100644 (file)
@@ -126,7 +126,7 @@ static ssize_t hfsplus_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
 {
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
-       struct inode *inode = file_inode(file)->i_mapping->host;
+       struct inode *inode = mapping->host;
        size_t count = iov_iter_count(iter);
        ssize_t ret;
 
index e8ef121..c13c8a2 100644 (file)
@@ -346,7 +346,7 @@ int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str)
 
        casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
        decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        astr = str->name;
        len = str->len;
        while (len > 0) {
index fa27980..60e6d33 100644 (file)
@@ -26,7 +26,7 @@ static int hpfs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
                /*return -ENOENT;*/
        x:
 
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        for (i = 0; i < l; i++)
                hash = partial_name_hash(hpfs_upcase(hpfs_sb(dentry->d_sb)->sb_cp_table,qstr->name[i]), hash);
        qstr->hash = end_name_hash(hash);
index 116a333..0f56deb 100644 (file)
@@ -590,6 +590,7 @@ static long ioctl_file_dedupe_range(struct file *file, void __user *arg)
                goto out;
        }
 
+       same->dest_count = count;
        ret = vfs_dedupe_file_range(file, same);
        if (ret)
                goto out;
index 2ce5b75..44af14b 100644 (file)
@@ -361,7 +361,6 @@ static int zisofs_readpage(struct file *file, struct page *page)
 
 const struct address_space_operations zisofs_aops = {
        .readpage = zisofs_readpage,
-       /* No sync_page operation supported? */
        /* No bmap operation supported */
 };
 
index 131dedc..761fade 100644 (file)
@@ -174,7 +174,7 @@ struct iso9660_options{
  * Compute the hash for the isofs name corresponding to the dentry.
  */
 static int
-isofs_hashi_common(struct qstr *qstr, int ms)
+isofs_hashi_common(const struct dentry *dentry, struct qstr *qstr, int ms)
 {
        const char *name;
        int len;
@@ -188,7 +188,7 @@ isofs_hashi_common(struct qstr *qstr, int ms)
                        len--;
        }
 
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        while (len--) {
                c = tolower(*name++);
                hash = partial_name_hash(c, hash);
@@ -231,7 +231,7 @@ static int isofs_dentry_cmp_common(
 static int
 isofs_hashi(const struct dentry *dentry, struct qstr *qstr)
 {
-       return isofs_hashi_common(qstr, 0);
+       return isofs_hashi_common(dentry, qstr, 0);
 }
 
 static int
@@ -246,7 +246,7 @@ isofs_dentry_cmpi(const struct dentry *parent, const struct dentry *dentry,
  * Compute the hash for the isofs name corresponding to the dentry.
  */
 static int
-isofs_hash_common(struct qstr *qstr, int ms)
+isofs_hash_common(const struct dentry *dentry, struct qstr *qstr, int ms)
 {
        const char *name;
        int len;
@@ -258,7 +258,7 @@ isofs_hash_common(struct qstr *qstr, int ms)
                        len--;
        }
 
-       qstr->hash = full_name_hash(name, len);
+       qstr->hash = full_name_hash(dentry, name, len);
 
        return 0;
 }
@@ -266,13 +266,13 @@ isofs_hash_common(struct qstr *qstr, int ms)
 static int
 isofs_hash_ms(const struct dentry *dentry, struct qstr *qstr)
 {
-       return isofs_hash_common(qstr, 1);
+       return isofs_hash_common(dentry, qstr, 1);
 }
 
 static int
 isofs_hashi_ms(const struct dentry *dentry, struct qstr *qstr)
 {
-       return isofs_hashi_common(qstr, 1);
+       return isofs_hashi_common(dentry, qstr, 1);
 }
 
 static int
index 84c4bf3..30eb33f 100644 (file)
@@ -81,6 +81,7 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
        struct jffs2_full_dirent *fd = NULL, *fd_list;
        uint32_t ino = 0;
        struct inode *inode = NULL;
+       unsigned int nhash;
 
        jffs2_dbg(1, "jffs2_lookup()\n");
 
@@ -89,11 +90,14 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
 
        dir_f = JFFS2_INODE_INFO(dir_i);
 
+       /* The 'nhash' on the fd_list is not the same as the dentry hash */
+       nhash = full_name_hash(NULL, target->d_name.name, target->d_name.len);
+
        mutex_lock(&dir_f->sem);
 
        /* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */
-       for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= target->d_name.hash; fd_list = fd_list->next) {
-               if (fd_list->nhash == target->d_name.hash &&
+       for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= nhash; fd_list = fd_list->next) {
+               if (fd_list->nhash == nhash &&
                    (!fd || fd_list->version > fd->version) &&
                    strlen(fd_list->name) == target->d_name.len &&
                    !strncmp(fd_list->name, target->d_name.name, target->d_name.len)) {
index bfebbf1..06a71db 100644 (file)
@@ -674,7 +674,7 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r
                }
        }
 
-       fd->nhash = full_name_hash(fd->name, rd->nsize);
+       fd->nhash = full_name_hash(NULL, fd->name, rd->nsize);
        fd->next = NULL;
        fd->name[rd->nsize] = '\0';
 
index 9ad5ba4..90431dd 100644 (file)
@@ -1100,7 +1100,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
        fd->next = NULL;
        fd->version = je32_to_cpu(rd->version);
        fd->ino = je32_to_cpu(rd->ino);
-       fd->nhash = full_name_hash(fd->name, checkedlen);
+       fd->nhash = full_name_hash(NULL, fd->name, checkedlen);
        fd->type = rd->type;
        jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
 
index bc53854..be7c8a6 100644 (file)
@@ -476,7 +476,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
                                fd->next = NULL;
                                fd->version = je32_to_cpu(spd->version);
                                fd->ino = je32_to_cpu(spd->ino);
-                               fd->nhash = full_name_hash(fd->name, checkedlen);
+                               fd->nhash = full_name_hash(NULL, fd->name, checkedlen);
                                fd->type = spd->type;
 
                                jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
index 7fb187a..cda9a36 100644 (file)
@@ -245,7 +245,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
 
        fd->version = je32_to_cpu(rd->version);
        fd->ino = je32_to_cpu(rd->ino);
-       fd->nhash = full_name_hash(name, namelen);
+       fd->nhash = full_name_hash(NULL, name, namelen);
        fd->type = rd->type;
        memcpy(fd->name, name, namelen);
        fd->name[namelen]=0;
@@ -598,7 +598,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
                jffs2_add_fd_to_list(c, fd, &dir_f->dents);
                mutex_unlock(&dir_f->sem);
        } else {
-               uint32_t nhash = full_name_hash(name, namelen);
+               uint32_t nhash = full_name_hash(NULL, name, namelen);
 
                fd = dir_f->dents;
                /* We don't actually want to reserve any space, but we do
index dd824d9..a37eb5f 100644 (file)
@@ -58,7 +58,6 @@ static ssize_t jfs_loglevel_proc_write(struct file *file,
 }
 
 static const struct file_operations jfs_loglevel_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = jfs_loglevel_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index a747521..a21ea8b 100644 (file)
@@ -2517,7 +2517,6 @@ static int jfs_lmstats_proc_open(struct inode *inode, struct file *file)
 }
 
 const struct file_operations jfs_lmstats_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = jfs_lmstats_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index e7fa9e5..489aaa1 100644 (file)
@@ -830,7 +830,6 @@ static int jfs_mpstat_proc_open(struct inode *inode, struct file *file)
 }
 
 const struct file_operations jfs_mpstat_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = jfs_mpstat_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index eddf2b6..2e58978 100644 (file)
@@ -3040,7 +3040,6 @@ static int jfs_txanchor_proc_open(struct inode *inode, struct file *file)
 }
 
 const struct file_operations jfs_txanchor_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = jfs_txanchor_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
@@ -3081,7 +3080,6 @@ static int jfs_txstats_proc_open(struct inode *inode, struct file *file)
 }
 
 const struct file_operations jfs_txstats_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = jfs_txstats_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index 5ad7748..5cde6d2 100644 (file)
@@ -3894,7 +3894,6 @@ static int jfs_xtstat_proc_open(struct inode *inode, struct file *file)
 }
 
 const struct file_operations jfs_xtstat_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = jfs_xtstat_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
index 539dedd..04baf0d 100644 (file)
@@ -1564,7 +1564,7 @@ static int jfs_ci_hash(const struct dentry *dir, struct qstr *this)
        unsigned long hash;
        int i;
 
-       hash = init_name_hash();
+       hash = init_name_hash(dir);
        for (i=0; i < this->len; i++)
                hash = partial_name_hash(tolower(this->name[i]), hash);
        this->hash = end_name_hash(hash);
index 8a65240..e57174d 100644 (file)
@@ -336,11 +336,11 @@ struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn)
  */
 static unsigned int kernfs_name_hash(const char *name, const void *ns)
 {
-       unsigned long hash = init_name_hash();
+       unsigned long hash = init_name_hash(ns);
        unsigned int len = strlen(name);
        while (len--)
                hash = partial_name_hash(*name++, hash);
-       hash = (end_name_hash(hash) ^ hash_ptr((void *)ns, 31));
+       hash = end_name_hash(hash);
        hash &= 0x7fffffffU;
        /* Reserve hash numbers 0, 1 and INT_MAX for magic directory entries */
        if (hash < 2)
index 2a0a984..8f72cb2 100644 (file)
@@ -64,7 +64,6 @@ static const struct file_operations lockd_end_grace_operations = {
        .read           = nlm_end_grace_read,
        .llseek         = default_llseek,
        .release        = simple_transaction_release,
-       .owner          = THIS_MODULE,
 };
 
 int __init
index 2d5336b..bcd754d 100644 (file)
@@ -95,7 +95,7 @@ static int beyond_eof(struct inode *inode, loff_t bix)
  * of each character and pick a prime nearby, preferably a bit-sparse
  * one.
  */
-static u32 hash_32(const char *s, int len, u32 seed)
+static u32 logfs_hash_32(const char *s, int len, u32 seed)
 {
        u32 hash = seed;
        int i;
@@ -159,7 +159,7 @@ static struct page *logfs_get_dd_page(struct inode *dir, struct dentry *dentry)
        struct qstr *name = &dentry->d_name;
        struct page *page;
        struct logfs_disk_dentry *dd;
-       u32 hash = hash_32(name->name, name->len, 0);
+       u32 hash = logfs_hash_32(name->name, name->len, 0);
        pgoff_t index;
        int round;
 
@@ -370,7 +370,7 @@ static int logfs_write_dir(struct inode *dir, struct dentry *dentry,
 {
        struct page *page;
        struct logfs_disk_dentry *dd;
-       u32 hash = hash_32(dentry->d_name.name, dentry->d_name.len, 0);
+       u32 hash = logfs_hash_32(dentry->d_name.name, dentry->d_name.len, 0);
        pgoff_t index;
        int round, err;
 
index 70580ab..ecb0b43 100644 (file)
@@ -1449,9 +1449,8 @@ static int follow_dotdot(struct nameidata *nd)
 }
 
 /*
- * This looks up the name in dcache, possibly revalidates the old dentry and
- * allocates a new one if not found or not valid.  In the need_lookup argument
- * returns whether i_op->lookup is necessary.
+ * This looks up the name in dcache and possibly revalidates the found dentry.
+ * NULL is returned if the dentry does not exist in the cache.
  */
 static struct dentry *lookup_dcache(const struct qstr *name,
                                    struct dentry *dir,
@@ -1890,9 +1889,9 @@ static inline unsigned int fold_hash(unsigned long x, unsigned long y)
  * payload bytes, to match the way that hash_name() iterates until it
  * finds the delimiter after the name.
  */
-unsigned int full_name_hash(const char *name, unsigned int len)
+unsigned int full_name_hash(const void *salt, const char *name, unsigned int len)
 {
-       unsigned long a, x = 0, y = 0;
+       unsigned long a, x = 0, y = (unsigned long)salt;
 
        for (;;) {
                if (!len)
@@ -1911,15 +1910,19 @@ done:
 EXPORT_SYMBOL(full_name_hash);
 
 /* Return the "hash_len" (hash and length) of a null-terminated string */
-u64 hashlen_string(const char *name)
+u64 hashlen_string(const void *salt, const char *name)
 {
-       unsigned long a = 0, x = 0, y = 0, adata, mask, len;
+       unsigned long a = 0, x = 0, y = (unsigned long)salt;
+       unsigned long adata, mask, len;
        const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
 
-       len = -sizeof(unsigned long);
+       len = 0;
+       goto inside;
+
        do {
                HASH_MIX(x, y, a);
                len += sizeof(unsigned long);
+inside:
                a = load_unaligned_zeropad(name+len);
        } while (!has_zero(a, &adata, &constants));
 
@@ -1935,15 +1938,19 @@ EXPORT_SYMBOL(hashlen_string);
  * Calculate the length and hash of the path component, and
  * return the "hash_len" as the result.
  */
-static inline u64 hash_name(const char *name)
+static inline u64 hash_name(const void *salt, const char *name)
 {
-       unsigned long a = 0, b, x = 0, y = 0, adata, bdata, mask, len;
+       unsigned long a = 0, b, x = 0, y = (unsigned long)salt;
+       unsigned long adata, bdata, mask, len;
        const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
 
-       len = -sizeof(unsigned long);
+       len = 0;
+       goto inside;
+
        do {
                HASH_MIX(x, y, a);
                len += sizeof(unsigned long);
+inside:
                a = load_unaligned_zeropad(name+len);
                b = a ^ REPEAT_BYTE('/');
        } while (!(has_zero(a, &adata, &constants) | has_zero(b, &bdata, &constants)));
@@ -1959,9 +1966,9 @@ static inline u64 hash_name(const char *name)
 #else  /* !CONFIG_DCACHE_WORD_ACCESS: Slow, byte-at-a-time version */
 
 /* Return the hash of a string of known length */
-unsigned int full_name_hash(const char *name, unsigned int len)
+unsigned int full_name_hash(const void *salt, const char *name, unsigned int len)
 {
-       unsigned long hash = init_name_hash();
+       unsigned long hash = init_name_hash(salt);
        while (len--)
                hash = partial_name_hash((unsigned char)*name++, hash);
        return end_name_hash(hash);
@@ -1969,9 +1976,9 @@ unsigned int full_name_hash(const char *name, unsigned int len)
 EXPORT_SYMBOL(full_name_hash);
 
 /* Return the "hash_len" (hash and length) of a null-terminated string */
-u64 hashlen_string(const char *name)
+u64 hashlen_string(const void *salt, const char *name)
 {
-       unsigned long hash = init_name_hash();
+       unsigned long hash = init_name_hash(salt);
        unsigned long len = 0, c;
 
        c = (unsigned char)*name;
@@ -1988,9 +1995,9 @@ EXPORT_SYMBOL(hashlen_string);
  * We know there's a real path component here of at least
  * one character.
  */
-static inline u64 hash_name(const char *name)
+static inline u64 hash_name(const void *salt, const char *name)
 {
-       unsigned long hash = init_name_hash();
+       unsigned long hash = init_name_hash(salt);
        unsigned long len = 0, c;
 
        c = (unsigned char)*name;
@@ -2030,7 +2037,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
                if (err)
                        return err;
 
-               hash_len = hash_name(name);
+               hash_len = hash_name(nd->path.dentry, name);
 
                type = LAST_NORM;
                if (name[0] == '.') switch (hashlen_len(hash_len)) {
@@ -2436,7 +2443,7 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
 
        this.name = name;
        this.len = len;
-       this.hash = full_name_hash(name, len);
+       this.hash = full_name_hash(base, name, len);
        if (!len)
                return ERR_PTR(-EACCES);
 
@@ -2489,7 +2496,7 @@ struct dentry *lookup_one_len_unlocked(const char *name,
 
        this.name = name;
        this.len = len;
-       this.hash = full_name_hash(name, len);
+       this.hash = full_name_hash(base, name, len);
        if (!len)
                return ERR_PTR(-EACCES);
 
@@ -4328,7 +4335,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
         * Check source == target.
         * On overlayfs need to look at underlying inodes.
         */
-       if (vfs_select_inode(old_dentry, 0) == vfs_select_inode(new_dentry, 0))
+       if (d_real_inode(old_dentry) == d_real_inode(new_dentry))
                return 0;
 
        error = may_delete(old_dir, old_dentry, is_dir);
index bfdad00..9add7ab 100644 (file)
@@ -139,7 +139,7 @@ ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
                int i;
 
                t = NCP_IO_TABLE(sb);
-               hash = init_name_hash();
+               hash = init_name_hash(dentry);
                for (i=0; i<this->len ; i++)
                        hash = partial_name_hash(ncp_tolower(t, this->name[i]),
                                                                        hash);
index 0c96528..487c560 100644 (file)
@@ -1102,7 +1102,6 @@ static const struct file_operations nfs_server_list_fops = {
        .read           = seq_read,
        .llseek         = seq_lseek,
        .release        = seq_release_net,
-       .owner          = THIS_MODULE,
 };
 
 static int nfs_volume_list_open(struct inode *inode, struct file *file);
@@ -1123,7 +1122,6 @@ static const struct file_operations nfs_volume_list_fops = {
        .read           = seq_read,
        .llseek         = seq_lseek,
        .release        = seq_release_net,
-       .owner          = THIS_MODULE,
 };
 
 /*
index 19d93d0..baaa388 100644 (file)
@@ -232,7 +232,7 @@ int nfs_readdir_make_qstr(struct qstr *string, const char *name, unsigned int le
         * in a page cache page which kmemleak does not scan.
         */
        kmemleak_not_leak(string->name);
-       string->hash = full_name_hash(name, len);
+       string->hash = full_name_hash(NULL, name, len);
        return 0;
 }
 
@@ -502,7 +502,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
                if (filename.len == 2 && filename.name[1] == '.')
                        return;
        }
-       filename.hash = full_name_hash(filename.name, filename.len);
+       filename.hash = full_name_hash(parent, filename.name, filename.len);
 
        dentry = d_lookup(parent, &filename);
 again:
@@ -734,7 +734,7 @@ struct page *get_cache_page(nfs_readdir_descriptor_t *desc)
        struct page *page;
 
        for (;;) {
-               page = read_cache_page(file_inode(desc->file)->i_mapping,
+               page = read_cache_page(desc->file->f_mapping,
                        desc->page_index, (filler_t *)nfs_readdir_filler, desc);
                if (IS_ERR(page) || grab_page(page))
                        break;
@@ -1397,19 +1397,18 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
        if (IS_ERR(label))
                goto out;
 
-       /* Protect against concurrent sillydeletes */
        trace_nfs_lookup_enter(dir, dentry, flags);
        error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
        if (error == -ENOENT)
                goto no_entry;
        if (error < 0) {
                res = ERR_PTR(error);
-               goto out_unblock_sillyrename;
+               goto out_label;
        }
        inode = nfs_fhget(dentry->d_sb, fhandle, fattr, label);
        res = ERR_CAST(inode);
        if (IS_ERR(res))
-               goto out_unblock_sillyrename;
+               goto out_label;
 
        /* Success: notify readdir to use READDIRPLUS */
        nfs_advise_use_readdirplus(dir);
@@ -1418,11 +1417,11 @@ no_entry:
        res = d_splice_alias(inode, dentry);
        if (res != NULL) {
                if (IS_ERR(res))
-                       goto out_unblock_sillyrename;
+                       goto out_label;
                dentry = res;
        }
        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
-out_unblock_sillyrename:
+out_label:
        trace_nfs_lookup_exit(dir, dentry, flags, error);
        nfs4_label_free(label);
 out:
index c7326c2..e6210ea 100644 (file)
@@ -244,9 +244,7 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq,
 /**
  * nfs_direct_IO - NFS address space operation for direct I/O
  * @iocb: target I/O control block
- * @iov: array of vectors that define I/O buffer
- * @pos: offset in file to begin the operation
- * @nr_segs: size of iovec array
+ * @iter: I/O buffer
  *
  * The presence of this routine in the address space ops vector means
  * the NFS client supports direct I/O. However, for most direct IO, we
index 5154fa6..5ea04d8 100644 (file)
@@ -623,7 +623,7 @@ void nfs_mark_page_unstable(struct page *page, struct nfs_commit_info *cinfo)
        if (!cinfo->dreq) {
                struct inode *inode = page_file_mapping(page)->host;
 
-               inc_zone_page_state(page, NR_UNSTABLE_NFS);
+               inc_node_page_state(page, NR_UNSTABLE_NFS);
                inc_wb_stat(&inode_to_bdi(inode)->wb, WB_RECLAIMABLE);
                __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
        }
index e1c74d3..593fa21 100644 (file)
@@ -898,7 +898,7 @@ nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg,
 static void
 nfs_clear_page_commit(struct page *page)
 {
-       dec_zone_page_state(page, NR_UNSTABLE_NFS);
+       dec_node_page_state(page, NR_UNSTABLE_NFS);
        dec_wb_stat(&inode_to_bdi(page_file_mapping(page)->host)->wb,
                    WB_RECLAIMABLE);
 }
index 9690cb4..e778777 100644 (file)
@@ -158,7 +158,6 @@ static const struct file_operations exports_proc_operations = {
        .read           = seq_read,
        .llseek         = seq_lseek,
        .release        = seq_release,
-       .owner          = THIS_MODULE,
 };
 
 static int exports_nfsd_open(struct inode *inode, struct file *file)
@@ -171,7 +170,6 @@ static const struct file_operations exports_nfsd_operations = {
        .read           = seq_read,
        .llseek         = seq_lseek,
        .release        = seq_release,
-       .owner          = THIS_MODULE,
 };
 
 static int export_features_show(struct seq_file *m, void *v)
@@ -217,7 +215,6 @@ static const struct file_operations pool_stats_operations = {
        .read           = seq_read,
        .llseek         = seq_lseek,
        .release        = nfsd_pool_stats_release,
-       .owner          = THIS_MODULE,
 };
 
 static struct file_operations reply_cache_stats_operations = {
index cd90878..d97338b 100644 (file)
@@ -84,7 +84,6 @@ static int nfsd_proc_open(struct inode *inode, struct file *file)
 }
 
 static const struct file_operations nfsd_proc_fops = {
-       .owner = THIS_MODULE,
        .open = nfsd_proc_open,
        .read  = seq_read,
        .llseek = seq_lseek,
index f40972d..e01287c 100644 (file)
@@ -1854,7 +1854,7 @@ int ntfs_read_inode_mount(struct inode *vi)
        /* Need this to sanity check attribute list references to $MFT. */
        vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number);
 
-       /* Provides readpage() and sync_page() for map_mft_record(). */
+       /* Provides readpage() for map_mft_record(). */
        vi->i_mapping->a_ops = &ntfs_mst_aops;
 
        ctx = ntfs_attr_get_search_ctx(ni, m);
index 443abec..3582583 100644 (file)
@@ -253,7 +253,7 @@ handle_name:
                err = (signed)nls_name.len;
                goto err_out;
        }
-       nls_name.hash = full_name_hash(nls_name.name, nls_name.len);
+       nls_name.hash = full_name_hash(dent, nls_name.name, nls_name.len);
 
        dent = d_add_ci(dent, dent_inode, &nls_name);
        kfree(nls_name.name);
index e97a371..af2adfc 100644 (file)
@@ -2426,7 +2426,7 @@ static int ocfs2_dio_end_io(struct kiocb *iocb,
 static ssize_t ocfs2_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
 {
        struct file *file = iocb->ki_filp;
-       struct inode *inode = file_inode(file)->i_mapping->host;
+       struct inode *inode = file->f_mapping->host;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        get_block_t *get_block;
 
index 004f2cb..8107d0d 100644 (file)
@@ -47,7 +47,7 @@
 #define DLM_HASH_BUCKETS       (DLM_HASH_PAGES * DLM_BUCKETS_PER_PAGE)
 
 /* Intended to make it easier for us to switch out hash functions */
-#define dlm_lockid_hash(_n, _l) full_name_hash(_n, _l)
+#define dlm_lockid_hash(_n, _l) full_name_hash(NULL, _n, _l)
 
 enum dlm_mle_type {
        DLM_MLE_BLOCK = 0,
index ab6a6cd..87e577a 100644 (file)
@@ -483,7 +483,7 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
        struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
        struct ocfs2_global_disk_dqblk dqblk;
        s64 spacechange, inodechange;
-       time_t olditime, oldbtime;
+       time64_t olditime, oldbtime;
 
        err = sb->s_op->quota_read(sb, type, (char *)&dqblk,
                                   sizeof(struct ocfs2_global_disk_dqblk),
index d205385..5bb44f7 100644 (file)
@@ -7344,7 +7344,7 @@ const struct xattr_handler ocfs2_xattr_trusted_handler = {
  * 'user' attributes support
  */
 static int ocfs2_xattr_user_get(const struct xattr_handler *handler,
-                               struct dentry *unusde, struct inode *inode,
+                               struct dentry *unused, struct inode *inode,
                                const char *name, void *buffer, size_t size)
 {
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
index 93ae3cd..bf66cf1 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -840,13 +840,13 @@ EXPORT_SYMBOL(file_path);
 int vfs_open(const struct path *path, struct file *file,
             const struct cred *cred)
 {
-       struct inode *inode = vfs_select_inode(path->dentry, file->f_flags);
+       struct dentry *dentry = d_real(path->dentry, NULL, file->f_flags);
 
-       if (IS_ERR(inode))
-               return PTR_ERR(inode);
+       if (IS_ERR(dentry))
+               return PTR_ERR(dentry);
 
        file->f_path = *path;
-       return do_dentry_open(file, inode, NULL, cred);
+       return do_dentry_open(file, d_backing_inode(dentry), NULL, cred);
 }
 
 struct file *dentry_open(const struct path *path, int flags,
index 8f2fa94..2e63e6d 100644 (file)
@@ -291,7 +291,7 @@ int orangefs_permission(struct inode *inode, int mask)
 }
 
 /* ORANGEDS2 implementation of VFS inode operations for files */
-struct inode_operations orangefs_file_inode_operations = {
+const struct inode_operations orangefs_file_inode_operations = {
        .get_acl = orangefs_get_acl,
        .set_acl = orangefs_set_acl,
        .setattr = orangefs_setattr,
index 5a60c50..7e8dfa9 100644 (file)
@@ -405,12 +405,8 @@ static int orangefs_rename(struct inode *old_dir,
        int ret;
 
        gossip_debug(GOSSIP_NAME_DEBUG,
-                    "orangefs_rename: called (%s/%s => %s/%s) ct=%d\n",
-                    old_dentry->d_parent->d_name.name,
-                    old_dentry->d_name.name,
-                    new_dentry->d_parent->d_name.name,
-                    new_dentry->d_name.name,
-                    d_count(new_dentry));
+                    "orangefs_rename: called (%pd2 => %pd2) ct=%d\n",
+                    old_dentry, new_dentry, d_count(new_dentry));
 
        new_op = op_alloc(ORANGEFS_VFS_OP_RENAME);
        if (!new_op)
@@ -442,7 +438,7 @@ static int orangefs_rename(struct inode *old_dir,
 }
 
 /* ORANGEFS implementation of VFS inode operations for directories */
-struct inode_operations orangefs_dir_inode_operations = {
+const struct inode_operations orangefs_dir_inode_operations = {
        .lookup = orangefs_lookup,
        .get_acl = orangefs_get_acl,
        .set_acl = orangefs_set_acl,
index c1181e5..4b6e132 100644 (file)
@@ -557,10 +557,10 @@ extern int hash_table_size;
 
 extern const struct address_space_operations orangefs_address_operations;
 extern struct backing_dev_info orangefs_backing_dev_info;
-extern struct inode_operations orangefs_file_inode_operations;
+extern const struct inode_operations orangefs_file_inode_operations;
 extern const struct file_operations orangefs_file_operations;
-extern struct inode_operations orangefs_symlink_inode_operations;
-extern struct inode_operations orangefs_dir_inode_operations;
+extern const struct inode_operations orangefs_symlink_inode_operations;
+extern const struct inode_operations orangefs_dir_inode_operations;
 extern const struct file_operations orangefs_dir_operations;
 extern const struct dentry_operations orangefs_dentry_operations;
 extern const struct file_operations orangefs_devreq_file_operations;
index 6418dd6..8fecf82 100644 (file)
@@ -8,7 +8,7 @@
 #include "orangefs-kernel.h"
 #include "orangefs-bufmap.h"
 
-struct inode_operations orangefs_symlink_inode_operations = {
+const struct inode_operations orangefs_symlink_inode_operations = {
        .readlink = generic_readlink,
        .get_link = simple_get_link,
        .setattr = orangefs_setattr,
index d1cdc60..d554e86 100644 (file)
@@ -351,36 +351,25 @@ static bool ovl_open_need_copy_up(int flags, enum ovl_path_type type,
        return true;
 }
 
-struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags)
+int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags)
 {
-       int err;
+       int err = 0;
        struct path realpath;
        enum ovl_path_type type;
 
-       if (d_is_dir(dentry))
-               return d_backing_inode(dentry);
-
        type = ovl_path_real(dentry, &realpath);
        if (ovl_open_need_copy_up(file_flags, type, realpath.dentry)) {
                err = ovl_want_write(dentry);
-               if (err)
-                       return ERR_PTR(err);
-
-               if (file_flags & O_TRUNC)
-                       err = ovl_copy_up_truncate(dentry);
-               else
-                       err = ovl_copy_up(dentry);
-               ovl_drop_write(dentry);
-               if (err)
-                       return ERR_PTR(err);
-
-               ovl_path_upper(dentry, &realpath);
+               if (!err) {
+                       if (file_flags & O_TRUNC)
+                               err = ovl_copy_up_truncate(dentry);
+                       else
+                               err = ovl_copy_up(dentry);
+                       ovl_drop_write(dentry);
+               }
        }
 
-       if (realpath.dentry->d_flags & DCACHE_OP_SELECT_INODE)
-               return realpath.dentry->d_op->d_select_inode(realpath.dentry, file_flags);
-
-       return d_backing_inode(realpath.dentry);
+       return err;
 }
 
 static const struct inode_operations ovl_file_inode_operations = {
index cfbca53..0d3f2ad 100644 (file)
@@ -179,7 +179,7 @@ ssize_t ovl_getxattr(struct dentry *dentry, struct inode *inode,
                     const char *name, void *value, size_t size);
 ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
 int ovl_removexattr(struct dentry *dentry, const char *name);
-struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags);
+int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags);
 
 struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
                            struct ovl_entry *oe);
index 9a7693d..5e254b3 100644 (file)
@@ -304,7 +304,9 @@ static void ovl_dentry_release(struct dentry *dentry)
        }
 }
 
-static struct dentry *ovl_d_real(struct dentry *dentry, struct inode *inode)
+static struct dentry *ovl_d_real(struct dentry *dentry,
+                                const struct inode *inode,
+                                unsigned int open_flags)
 {
        struct dentry *real;
 
@@ -314,6 +316,16 @@ static struct dentry *ovl_d_real(struct dentry *dentry, struct inode *inode)
                goto bug;
        }
 
+       if (d_is_negative(dentry))
+               return dentry;
+
+       if (open_flags) {
+               int err = ovl_open_maybe_copy_up(dentry, open_flags);
+
+               if (err)
+                       return ERR_PTR(err);
+       }
+
        real = ovl_dentry_upper(dentry);
        if (real && (!inode || inode == d_inode(real)))
                return real;
@@ -326,9 +338,7 @@ static struct dentry *ovl_d_real(struct dentry *dentry, struct inode *inode)
                return real;
 
        /* Handle recursion */
-       if (real->d_flags & DCACHE_OP_REAL)
-               return real->d_op->d_real(real, inode);
-
+       return d_real(real, inode, open_flags);
 bug:
        WARN(1, "ovl_d_real(%pd4, %s:%lu\n): real dentry not found\n", dentry,
             inode ? inode->i_sb->s_id : "NULL", inode ? inode->i_ino : 0);
@@ -378,13 +388,11 @@ static int ovl_dentry_weak_revalidate(struct dentry *dentry, unsigned int flags)
 
 static const struct dentry_operations ovl_dentry_operations = {
        .d_release = ovl_dentry_release,
-       .d_select_inode = ovl_d_select_inode,
        .d_real = ovl_d_real,
 };
 
 static const struct dentry_operations ovl_reval_dentry_operations = {
        .d_release = ovl_dentry_release,
-       .d_select_inode = ovl_d_select_inode,
        .d_real = ovl_d_real,
        .d_revalidate = ovl_dentry_revalidate,
        .d_weak_revalidate = ovl_dentry_weak_revalidate,
index a11eb71..31370da 100644 (file)
@@ -1024,23 +1024,107 @@ static ssize_t oom_adj_read(struct file *file, char __user *buf, size_t count,
        char buffer[PROC_NUMBUF];
        int oom_adj = OOM_ADJUST_MIN;
        size_t len;
-       unsigned long flags;
 
        if (!task)
                return -ESRCH;
-       if (lock_task_sighand(task, &flags)) {
-               if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MAX)
-                       oom_adj = OOM_ADJUST_MAX;
-               else
-                       oom_adj = (task->signal->oom_score_adj * -OOM_DISABLE) /
-                                 OOM_SCORE_ADJ_MAX;
-               unlock_task_sighand(task, &flags);
-       }
+       if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MAX)
+               oom_adj = OOM_ADJUST_MAX;
+       else
+               oom_adj = (task->signal->oom_score_adj * -OOM_DISABLE) /
+                         OOM_SCORE_ADJ_MAX;
        put_task_struct(task);
        len = snprintf(buffer, sizeof(buffer), "%d\n", oom_adj);
        return simple_read_from_buffer(buf, count, ppos, buffer, len);
 }
 
+static int __set_oom_adj(struct file *file, int oom_adj, bool legacy)
+{
+       static DEFINE_MUTEX(oom_adj_mutex);
+       struct mm_struct *mm = NULL;
+       struct task_struct *task;
+       int err = 0;
+
+       task = get_proc_task(file_inode(file));
+       if (!task)
+               return -ESRCH;
+
+       mutex_lock(&oom_adj_mutex);
+       if (legacy) {
+               if (oom_adj < task->signal->oom_score_adj &&
+                               !capable(CAP_SYS_RESOURCE)) {
+                       err = -EACCES;
+                       goto err_unlock;
+               }
+               /*
+                * /proc/pid/oom_adj is provided for legacy purposes, ask users to use
+                * /proc/pid/oom_score_adj instead.
+                */
+               pr_warn_once("%s (%d): /proc/%d/oom_adj is deprecated, please use /proc/%d/oom_score_adj instead.\n",
+                         current->comm, task_pid_nr(current), task_pid_nr(task),
+                         task_pid_nr(task));
+       } else {
+               if ((short)oom_adj < task->signal->oom_score_adj_min &&
+                               !capable(CAP_SYS_RESOURCE)) {
+                       err = -EACCES;
+                       goto err_unlock;
+               }
+       }
+
+       /*
+        * Make sure we will check other processes sharing the mm if this is
+        * not vfrok which wants its own oom_score_adj.
+        * pin the mm so it doesn't go away and get reused after task_unlock
+        */
+       if (!task->vfork_done) {
+               struct task_struct *p = find_lock_task_mm(task);
+
+               if (p) {
+                       if (atomic_read(&p->mm->mm_users) > 1) {
+                               mm = p->mm;
+                               atomic_inc(&mm->mm_count);
+                       }
+                       task_unlock(p);
+               }
+       }
+
+       task->signal->oom_score_adj = oom_adj;
+       if (!legacy && has_capability_noaudit(current, CAP_SYS_RESOURCE))
+               task->signal->oom_score_adj_min = (short)oom_adj;
+       trace_oom_score_adj_update(task);
+
+       if (mm) {
+               struct task_struct *p;
+
+               rcu_read_lock();
+               for_each_process(p) {
+                       if (same_thread_group(task, p))
+                               continue;
+
+                       /* do not touch kernel threads or the global init */
+                       if (p->flags & PF_KTHREAD || is_global_init(p))
+                               continue;
+
+                       task_lock(p);
+                       if (!p->vfork_done && process_shares_mm(p, mm)) {
+                               pr_info("updating oom_score_adj for %d (%s) from %d to %d because it shares mm with %d (%s). Report if this is unexpected.\n",
+                                               task_pid_nr(p), p->comm,
+                                               p->signal->oom_score_adj, oom_adj,
+                                               task_pid_nr(task), task->comm);
+                               p->signal->oom_score_adj = oom_adj;
+                               if (!legacy && has_capability_noaudit(current, CAP_SYS_RESOURCE))
+                                       p->signal->oom_score_adj_min = (short)oom_adj;
+                       }
+                       task_unlock(p);
+               }
+               rcu_read_unlock();
+               mmdrop(mm);
+       }
+err_unlock:
+       mutex_unlock(&oom_adj_mutex);
+       put_task_struct(task);
+       return err;
+}
+
 /*
  * /proc/pid/oom_adj exists solely for backwards compatibility with previous
  * kernels.  The effective policy is defined by oom_score_adj, which has a
@@ -1054,10 +1138,8 @@ static ssize_t oom_adj_read(struct file *file, char __user *buf, size_t count,
 static ssize_t oom_adj_write(struct file *file, const char __user *buf,
                             size_t count, loff_t *ppos)
 {
-       struct task_struct *task;
        char buffer[PROC_NUMBUF];
        int oom_adj;
-       unsigned long flags;
        int err;
 
        memset(buffer, 0, sizeof(buffer));
@@ -1077,23 +1159,6 @@ static ssize_t oom_adj_write(struct file *file, const char __user *buf,
                goto out;
        }
 
-       task = get_proc_task(file_inode(file));
-       if (!task) {
-               err = -ESRCH;
-               goto out;
-       }
-
-       task_lock(task);
-       if (!task->mm) {
-               err = -EINVAL;
-               goto err_task_lock;
-       }
-
-       if (!lock_task_sighand(task, &flags)) {
-               err = -ESRCH;
-               goto err_task_lock;
-       }
-
        /*
         * Scale /proc/pid/oom_score_adj appropriately ensuring that a maximum
         * value is always attainable.
@@ -1103,27 +1168,7 @@ static ssize_t oom_adj_write(struct file *file, const char __user *buf,
        else
                oom_adj = (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;
 
-       if (oom_adj < task->signal->oom_score_adj &&
-           !capable(CAP_SYS_RESOURCE)) {
-               err = -EACCES;
-               goto err_sighand;
-       }
-
-       /*
-        * /proc/pid/oom_adj is provided for legacy purposes, ask users to use
-        * /proc/pid/oom_score_adj instead.
-        */
-       pr_warn_once("%s (%d): /proc/%d/oom_adj is deprecated, please use /proc/%d/oom_score_adj instead.\n",
-                 current->comm, task_pid_nr(current), task_pid_nr(task),
-                 task_pid_nr(task));
-
-       task->signal->oom_score_adj = oom_adj;
-       trace_oom_score_adj_update(task);
-err_sighand:
-       unlock_task_sighand(task, &flags);
-err_task_lock:
-       task_unlock(task);
-       put_task_struct(task);
+       err = __set_oom_adj(file, oom_adj, true);
 out:
        return err < 0 ? err : count;
 }
@@ -1140,15 +1185,11 @@ static ssize_t oom_score_adj_read(struct file *file, char __user *buf,
        struct task_struct *task = get_proc_task(file_inode(file));
        char buffer[PROC_NUMBUF];
        short oom_score_adj = OOM_SCORE_ADJ_MIN;
-       unsigned long flags;
        size_t len;
 
        if (!task)
                return -ESRCH;
-       if (lock_task_sighand(task, &flags)) {
-               oom_score_adj = task->signal->oom_score_adj;
-               unlock_task_sighand(task, &flags);
-       }
+       oom_score_adj = task->signal->oom_score_adj;
        put_task_struct(task);
        len = snprintf(buffer, sizeof(buffer), "%hd\n", oom_score_adj);
        return simple_read_from_buffer(buf, count, ppos, buffer, len);
@@ -1157,9 +1198,7 @@ static ssize_t oom_score_adj_read(struct file *file, char __user *buf,
 static ssize_t oom_score_adj_write(struct file *file, const char __user *buf,
                                        size_t count, loff_t *ppos)
 {
-       struct task_struct *task;
        char buffer[PROC_NUMBUF];
-       unsigned long flags;
        int oom_score_adj;
        int err;
 
@@ -1180,39 +1219,7 @@ static ssize_t oom_score_adj_write(struct file *file, const char __user *buf,
                goto out;
        }
 
-       task = get_proc_task(file_inode(file));
-       if (!task) {
-               err = -ESRCH;
-               goto out;
-       }
-
-       task_lock(task);
-       if (!task->mm) {
-               err = -EINVAL;
-               goto err_task_lock;
-       }
-
-       if (!lock_task_sighand(task, &flags)) {
-               err = -ESRCH;
-               goto err_task_lock;
-       }
-
-       if ((short)oom_score_adj < task->signal->oom_score_adj_min &&
-                       !capable(CAP_SYS_RESOURCE)) {
-               err = -EACCES;
-               goto err_sighand;
-       }
-
-       task->signal->oom_score_adj = (short)oom_score_adj;
-       if (has_capability_noaudit(current, CAP_SYS_RESOURCE))
-               task->signal->oom_score_adj_min = (short)oom_score_adj;
-       trace_oom_score_adj_update(task);
-
-err_sighand:
-       unlock_task_sighand(task, &flags);
-err_task_lock:
-       task_unlock(task);
-       put_task_struct(task);
+       err = __set_oom_adj(file, oom_score_adj, false);
 out:
        return err < 0 ? err : count;
 }
index cf301a9..09e18fd 100644 (file)
@@ -40,7 +40,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
        si_swapinfo(&i);
        committed = percpu_counter_read_positive(&vm_committed_as);
 
-       cached = global_page_state(NR_FILE_PAGES) -
+       cached = global_node_page_state(NR_FILE_PAGES) -
                        total_swapcache_pages() - i.bufferram;
        if (cached < 0)
                cached = 0;
@@ -138,23 +138,23 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
 #endif
                K(i.totalswap),
                K(i.freeswap),
-               K(global_page_state(NR_FILE_DIRTY)),
-               K(global_page_state(NR_WRITEBACK)),
-               K(global_page_state(NR_ANON_PAGES)),
-               K(global_page_state(NR_FILE_MAPPED)),
+               K(global_node_page_state(NR_FILE_DIRTY)),
+               K(global_node_page_state(NR_WRITEBACK)),
+               K(global_node_page_state(NR_ANON_MAPPED)),
+               K(global_node_page_state(NR_FILE_MAPPED)),
                K(i.sharedram),
                K(global_page_state(NR_SLAB_RECLAIMABLE) +
                                global_page_state(NR_SLAB_UNRECLAIMABLE)),
                K(global_page_state(NR_SLAB_RECLAIMABLE)),
                K(global_page_state(NR_SLAB_UNRECLAIMABLE)),
-               global_page_state(NR_KERNEL_STACK) * THREAD_SIZE / 1024,
+               global_page_state(NR_KERNEL_STACK_KB),
                K(global_page_state(NR_PAGETABLE)),
 #ifdef CONFIG_QUICKLIST
                K(quicklist_total_size()),
 #endif
-               K(global_page_state(NR_UNSTABLE_NFS)),
+               K(global_node_page_state(NR_UNSTABLE_NFS)),
                K(global_page_state(NR_BOUNCE)),
-               K(global_page_state(NR_WRITEBACK_TEMP)),
+               K(global_node_page_state(NR_WRITEBACK_TEMP)),
                K(vm_commit_limit()),
                K(committed),
                (unsigned long)VMALLOC_TOTAL >> 10,
@@ -164,9 +164,9 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
                , atomic_long_read(&num_poisoned_pages) << (PAGE_SHIFT - 10)
 #endif
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-               , K(global_page_state(NR_ANON_THPS) * HPAGE_PMD_NR)
-               , K(global_page_state(NR_SHMEM_THPS) * HPAGE_PMD_NR)
-               , K(global_page_state(NR_SHMEM_PMDMAPPED) * HPAGE_PMD_NR)
+               , K(global_node_page_state(NR_ANON_THPS) * HPAGE_PMD_NR)
+               , K(global_node_page_state(NR_SHMEM_THPS) * HPAGE_PMD_NR)
+               , K(global_node_page_state(NR_SHMEM_PMDMAPPED) * HPAGE_PMD_NR)
 #endif
 #ifdef CONFIG_CMA
                , K(totalcma_pages)
index 5e57c3e..b59db94 100644 (file)
@@ -623,7 +623,7 @@ static bool proc_sys_fill_cache(struct file *file,
 
        qname.name = table->procname;
        qname.len  = strlen(table->procname);
-       qname.hash = full_name_hash(qname.name, qname.len);
+       qname.hash = full_name_hash(dir, qname.name, qname.len);
 
        child = d_lookup(dir, &qname);
        if (!child) {
index ff21980..b1322dd 100644 (file)
@@ -1133,7 +1133,7 @@ static void dquot_decr_inodes(struct dquot *dquot, qsize_t number)
        else
                dquot->dq_dqb.dqb_curinodes = 0;
        if (dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit)
-               dquot->dq_dqb.dqb_itime = (time_t) 0;
+               dquot->dq_dqb.dqb_itime = (time64_t) 0;
        clear_bit(DQ_INODES_B, &dquot->dq_flags);
 }
 
@@ -1145,7 +1145,7 @@ static void dquot_decr_space(struct dquot *dquot, qsize_t number)
        else
                dquot->dq_dqb.dqb_curspace = 0;
        if (dquot->dq_dqb.dqb_curspace <= dquot->dq_dqb.dqb_bsoftlimit)
-               dquot->dq_dqb.dqb_btime = (time_t) 0;
+               dquot->dq_dqb.dqb_btime = (time64_t) 0;
        clear_bit(DQ_BLKS_B, &dquot->dq_flags);
 }
 
@@ -1292,7 +1292,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes,
        if (dquot->dq_dqb.dqb_isoftlimit &&
            newinodes > dquot->dq_dqb.dqb_isoftlimit &&
            dquot->dq_dqb.dqb_itime &&
-           get_seconds() >= dquot->dq_dqb.dqb_itime &&
+           ktime_get_real_seconds() >= dquot->dq_dqb.dqb_itime &&
             !ignore_hardlimit(dquot)) {
                prepare_warning(warn, dquot, QUOTA_NL_ISOFTLONGWARN);
                return -EDQUOT;
@@ -1302,7 +1302,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes,
            newinodes > dquot->dq_dqb.dqb_isoftlimit &&
            dquot->dq_dqb.dqb_itime == 0) {
                prepare_warning(warn, dquot, QUOTA_NL_ISOFTWARN);
-               dquot->dq_dqb.dqb_itime = get_seconds() +
+               dquot->dq_dqb.dqb_itime = ktime_get_real_seconds() +
                    sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type].dqi_igrace;
        }
 
@@ -1334,7 +1334,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc,
        if (dquot->dq_dqb.dqb_bsoftlimit &&
            tspace > dquot->dq_dqb.dqb_bsoftlimit &&
            dquot->dq_dqb.dqb_btime &&
-           get_seconds() >= dquot->dq_dqb.dqb_btime &&
+           ktime_get_real_seconds() >= dquot->dq_dqb.dqb_btime &&
             !ignore_hardlimit(dquot)) {
                if (!prealloc)
                        prepare_warning(warn, dquot, QUOTA_NL_BSOFTLONGWARN);
@@ -1346,7 +1346,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc,
            dquot->dq_dqb.dqb_btime == 0) {
                if (!prealloc) {
                        prepare_warning(warn, dquot, QUOTA_NL_BSOFTWARN);
-                       dquot->dq_dqb.dqb_btime = get_seconds() +
+                       dquot->dq_dqb.dqb_btime = ktime_get_real_seconds() +
                            sb_dqopt(sb)->info[dquot->dq_id.type].dqi_bgrace;
                }
                else
@@ -2695,7 +2695,7 @@ static int do_set_dqblk(struct dquot *dquot, struct qc_dqblk *di)
                        clear_bit(DQ_BLKS_B, &dquot->dq_flags);
                } else if (!(di->d_fieldmask & QC_SPC_TIMER))
                        /* Set grace only if user hasn't provided his own... */
-                       dm->dqb_btime = get_seconds() + dqi->dqi_bgrace;
+                       dm->dqb_btime = ktime_get_real_seconds() + dqi->dqi_bgrace;
        }
        if (check_ilim) {
                if (!dm->dqb_isoftlimit ||
@@ -2704,7 +2704,7 @@ static int do_set_dqblk(struct dquot *dquot, struct qc_dqblk *di)
                        clear_bit(DQ_INODES_B, &dquot->dq_flags);
                } else if (!(di->d_fieldmask & QC_INO_TIMER))
                        /* Set grace only if user hasn't provided his own... */
-                       dm->dqb_itime = get_seconds() + dqi->dqi_igrace;
+                       dm->dqb_itime = ktime_get_real_seconds() + dqi->dqi_igrace;
        }
        if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit ||
            dm->dqb_isoftlimit)
index 90b60c0..a42de45 100644 (file)
@@ -33,7 +33,7 @@ static int sysv_hash(const struct dentry *dentry, struct qstr *qstr)
           function. */
        if (qstr->len > SYSV_NAMELEN) {
                qstr->len = SYSV_NAMELEN;
-               qstr->hash = full_name_hash(qstr->name, qstr->len);
+               qstr->hash = full_name_hash(dentry, qstr->name, qstr->len);
        }
        return 0;
 }
index 4a0e48f..ad40b64 100644 (file)
@@ -541,9 +541,6 @@ void tracefs_remove(struct dentry *dentry)
                return;
 
        parent = dentry->d_parent;
-       if (!parent || !parent->d_inode)
-               return;
-
        inode_lock(parent->d_inode);
        ret = __tracefs_remove(dentry, parent);
        inode_unlock(parent->d_inode);
@@ -566,10 +563,6 @@ void tracefs_remove_recursive(struct dentry *dentry)
        if (IS_ERR_OR_NULL(dentry))
                return;
 
-       parent = dentry->d_parent;
-       if (!parent || !parent->d_inode)
-               return;
-
        parent = dentry;
  down:
        inode_lock(parent->d_inode);
index 57dcced..fa3bda1 100644 (file)
@@ -279,12 +279,6 @@ struct ufs_dir_entry *ufs_find_entry(struct inode *dir, const struct qstr *qstr,
                        de = (struct ufs_dir_entry *) kaddr;
                        kaddr += ufs_last_byte(dir, n) - reclen;
                        while ((char *) de <= kaddr) {
-                               if (de->d_reclen == 0) {
-                                       ufs_error(dir->i_sb, __func__,
-                                                 "zero-length directory entry");
-                                       ufs_put_page(page);
-                                       goto out;
-                               }
                                if (ufs_match(sb, namelen, name, de))
                                        goto found;
                                de = ufs_next_entry(sb, de);
@@ -414,11 +408,8 @@ ufs_validate_entry(struct super_block *sb, char *base,
 {
        struct ufs_dir_entry *de = (struct ufs_dir_entry*)(base + offset);
        struct ufs_dir_entry *p = (struct ufs_dir_entry*)(base + (offset&mask));
-       while ((char*)p < (char*)de) {
-               if (p->d_reclen == 0)
-                       break;
+       while ((char*)p < (char*)de)
                p = ufs_next_entry(sb, p);
-       }
        return (char *)p - base;
 }
 
@@ -469,12 +460,6 @@ ufs_readdir(struct file *file, struct dir_context *ctx)
                de = (struct ufs_dir_entry *)(kaddr+offset);
                limit = kaddr + ufs_last_byte(inode, n) - UFS_DIR_REC_LEN(1);
                for ( ;(char*)de <= limit; de = ufs_next_entry(sb, de)) {
-                       if (de->d_reclen == 0) {
-                               ufs_error(sb, __func__,
-                                       "zero-length directory entry");
-                               ufs_put_page(page);
-                               return -EIO;
-                       }
                        if (de->d_ino) {
                                unsigned char d_type = DT_UNKNOWN;
 
index 8686df6..d266e83 100644 (file)
@@ -128,7 +128,6 @@ static int xqm_proc_open(struct inode *inode, struct file *file)
 }
 
 static const struct file_operations xqm_proc_fops = {
-       .owner          = THIS_MODULE,
        .open           = xqm_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
diff --git a/include/dt-bindings/pinctrl/stm32f746-pinfunc.h b/include/dt-bindings/pinctrl/stm32f746-pinfunc.h
new file mode 100644 (file)
index 0000000..6348c6a
--- /dev/null
@@ -0,0 +1,1324 @@
+#ifndef _DT_BINDINGS_STM32F746_PINFUNC_H
+#define _DT_BINDINGS_STM32F746_PINFUNC_H
+
+#define STM32F746_PA0_FUNC_GPIO 0x0
+#define STM32F746_PA0_FUNC_TIM2_CH1_TIM2_ETR 0x2
+#define STM32F746_PA0_FUNC_TIM5_CH1 0x3
+#define STM32F746_PA0_FUNC_TIM8_ETR 0x4
+#define STM32F746_PA0_FUNC_USART2_CTS 0x8
+#define STM32F746_PA0_FUNC_UART4_TX 0x9
+#define STM32F746_PA0_FUNC_SAI2_SD_B 0xb
+#define STM32F746_PA0_FUNC_ETH_MII_CRS 0xc
+#define STM32F746_PA0_FUNC_EVENTOUT 0x10
+#define STM32F746_PA0_FUNC_ANALOG 0x11
+
+#define STM32F746_PA1_FUNC_GPIO 0x100
+#define STM32F746_PA1_FUNC_TIM2_CH2 0x102
+#define STM32F746_PA1_FUNC_TIM5_CH2 0x103
+#define STM32F746_PA1_FUNC_USART2_RTS 0x108
+#define STM32F746_PA1_FUNC_UART4_RX 0x109
+#define STM32F746_PA1_FUNC_QUADSPI_BK1_IO3 0x10a
+#define STM32F746_PA1_FUNC_SAI2_MCLK_B 0x10b
+#define STM32F746_PA1_FUNC_ETH_MII_RX_CLK_ETH_RMII_REF_CLK 0x10c
+#define STM32F746_PA1_FUNC_LCD_R2 0x10f
+#define STM32F746_PA1_FUNC_EVENTOUT 0x110
+#define STM32F746_PA1_FUNC_ANALOG 0x111
+
+#define STM32F746_PA2_FUNC_GPIO 0x200
+#define STM32F746_PA2_FUNC_TIM2_CH3 0x202
+#define STM32F746_PA2_FUNC_TIM5_CH3 0x203
+#define STM32F746_PA2_FUNC_TIM9_CH1 0x204
+#define STM32F746_PA2_FUNC_USART2_TX 0x208
+#define STM32F746_PA2_FUNC_SAI2_SCK_B 0x209
+#define STM32F746_PA2_FUNC_ETH_MDIO 0x20c
+#define STM32F746_PA2_FUNC_LCD_R1 0x20f
+#define STM32F746_PA2_FUNC_EVENTOUT 0x210
+#define STM32F746_PA2_FUNC_ANALOG 0x211
+
+#define STM32F746_PA3_FUNC_GPIO 0x300
+#define STM32F746_PA3_FUNC_TIM2_CH4 0x302
+#define STM32F746_PA3_FUNC_TIM5_CH4 0x303
+#define STM32F746_PA3_FUNC_TIM9_CH2 0x304
+#define STM32F746_PA3_FUNC_USART2_RX 0x308
+#define STM32F746_PA3_FUNC_OTG_HS_ULPI_D0 0x30b
+#define STM32F746_PA3_FUNC_ETH_MII_COL 0x30c
+#define STM32F746_PA3_FUNC_LCD_B5 0x30f
+#define STM32F746_PA3_FUNC_EVENTOUT 0x310
+#define STM32F746_PA3_FUNC_ANALOG 0x311
+
+#define STM32F746_PA4_FUNC_GPIO 0x400
+#define STM32F746_PA4_FUNC_SPI1_NSS_I2S1_WS 0x406
+#define STM32F746_PA4_FUNC_SPI3_NSS_I2S3_WS 0x407
+#define STM32F746_PA4_FUNC_USART2_CK 0x408
+#define STM32F746_PA4_FUNC_OTG_HS_SOF 0x40d
+#define STM32F746_PA4_FUNC_DCMI_HSYNC 0x40e
+#define STM32F746_PA4_FUNC_LCD_VSYNC 0x40f
+#define STM32F746_PA4_FUNC_EVENTOUT 0x410
+#define STM32F746_PA4_FUNC_ANALOG 0x411
+
+#define STM32F746_PA5_FUNC_GPIO 0x500
+#define STM32F746_PA5_FUNC_TIM2_CH1_TIM2_ETR 0x502
+#define STM32F746_PA5_FUNC_TIM8_CH1N 0x504
+#define STM32F746_PA5_FUNC_SPI1_SCK_I2S1_CK 0x506
+#define STM32F746_PA5_FUNC_OTG_HS_ULPI_CK 0x50b
+#define STM32F746_PA5_FUNC_LCD_R4 0x50f
+#define STM32F746_PA5_FUNC_EVENTOUT 0x510
+#define STM32F746_PA5_FUNC_ANALOG 0x511
+
+#define STM32F746_PA6_FUNC_GPIO 0x600
+#define STM32F746_PA6_FUNC_TIM1_BKIN 0x602
+#define STM32F746_PA6_FUNC_TIM3_CH1 0x603
+#define STM32F746_PA6_FUNC_TIM8_BKIN 0x604
+#define STM32F746_PA6_FUNC_SPI1_MISO 0x606
+#define STM32F746_PA6_FUNC_TIM13_CH1 0x60a
+#define STM32F746_PA6_FUNC_DCMI_PIXCLK 0x60e
+#define STM32F746_PA6_FUNC_LCD_G2 0x60f
+#define STM32F746_PA6_FUNC_EVENTOUT 0x610
+#define STM32F746_PA6_FUNC_ANALOG 0x611
+
+#define STM32F746_PA7_FUNC_GPIO 0x700
+#define STM32F746_PA7_FUNC_TIM1_CH1N 0x702
+#define STM32F746_PA7_FUNC_TIM3_CH2 0x703
+#define STM32F746_PA7_FUNC_TIM8_CH1N 0x704
+#define STM32F746_PA7_FUNC_SPI1_MOSI_I2S1_SD 0x706
+#define STM32F746_PA7_FUNC_TIM14_CH1 0x70a
+#define STM32F746_PA7_FUNC_ETH_MII_RX_DV_ETH_RMII_CRS_DV 0x70c
+#define STM32F746_PA7_FUNC_FMC_SDNWE 0x70d
+#define STM32F746_PA7_FUNC_EVENTOUT 0x710
+#define STM32F746_PA7_FUNC_ANALOG 0x711
+
+#define STM32F746_PA8_FUNC_GPIO 0x800
+#define STM32F746_PA8_FUNC_MCO1 0x801
+#define STM32F746_PA8_FUNC_TIM1_CH1 0x802
+#define STM32F746_PA8_FUNC_TIM8_BKIN2 0x804
+#define STM32F746_PA8_FUNC_I2C3_SCL 0x805
+#define STM32F746_PA8_FUNC_USART1_CK 0x808
+#define STM32F746_PA8_FUNC_OTG_FS_SOF 0x80b
+#define STM32F746_PA8_FUNC_LCD_R6 0x80f
+#define STM32F746_PA8_FUNC_EVENTOUT 0x810
+#define STM32F746_PA8_FUNC_ANALOG 0x811
+
+#define STM32F746_PA9_FUNC_GPIO 0x900
+#define STM32F746_PA9_FUNC_TIM1_CH2 0x902
+#define STM32F746_PA9_FUNC_I2C3_SMBA 0x905
+#define STM32F746_PA9_FUNC_SPI2_SCK_I2S2_CK 0x906
+#define STM32F746_PA9_FUNC_USART1_TX 0x908
+#define STM32F746_PA9_FUNC_DCMI_D0 0x90e
+#define STM32F746_PA9_FUNC_EVENTOUT 0x910
+#define STM32F746_PA9_FUNC_ANALOG 0x911
+
+#define STM32F746_PA10_FUNC_GPIO 0xa00
+#define STM32F746_PA10_FUNC_TIM1_CH3 0xa02
+#define STM32F746_PA10_FUNC_USART1_RX 0xa08
+#define STM32F746_PA10_FUNC_OTG_FS_ID 0xa0b
+#define STM32F746_PA10_FUNC_DCMI_D1 0xa0e
+#define STM32F746_PA10_FUNC_EVENTOUT 0xa10
+#define STM32F746_PA10_FUNC_ANALOG 0xa11
+
+#define STM32F746_PA11_FUNC_GPIO 0xb00
+#define STM32F746_PA11_FUNC_TIM1_CH4 0xb02
+#define STM32F746_PA11_FUNC_USART1_CTS 0xb08
+#define STM32F746_PA11_FUNC_CAN1_RX 0xb0a
+#define STM32F746_PA11_FUNC_OTG_FS_DM 0xb0b
+#define STM32F746_PA11_FUNC_LCD_R4 0xb0f
+#define STM32F746_PA11_FUNC_EVENTOUT 0xb10
+#define STM32F746_PA11_FUNC_ANALOG 0xb11
+
+#define STM32F746_PA12_FUNC_GPIO 0xc00
+#define STM32F746_PA12_FUNC_TIM1_ETR 0xc02
+#define STM32F746_PA12_FUNC_USART1_RTS 0xc08
+#define STM32F746_PA12_FUNC_SAI2_FS_B 0xc09
+#define STM32F746_PA12_FUNC_CAN1_TX 0xc0a
+#define STM32F746_PA12_FUNC_OTG_FS_DP 0xc0b
+#define STM32F746_PA12_FUNC_LCD_R5 0xc0f
+#define STM32F746_PA12_FUNC_EVENTOUT 0xc10
+#define STM32F746_PA12_FUNC_ANALOG 0xc11
+
+#define STM32F746_PA13_FUNC_GPIO 0xd00
+#define STM32F746_PA13_FUNC_JTMS_SWDIO 0xd01
+#define STM32F746_PA13_FUNC_EVENTOUT 0xd10
+#define STM32F746_PA13_FUNC_ANALOG 0xd11
+
+#define STM32F746_PA14_FUNC_GPIO 0xe00
+#define STM32F746_PA14_FUNC_JTCK_SWCLK 0xe01
+#define STM32F746_PA14_FUNC_EVENTOUT 0xe10
+#define STM32F746_PA14_FUNC_ANALOG 0xe11
+
+#define STM32F746_PA15_FUNC_GPIO 0xf00
+#define STM32F746_PA15_FUNC_JTDI 0xf01
+#define STM32F746_PA15_FUNC_TIM2_CH1_TIM2_ETR 0xf02
+#define STM32F746_PA15_FUNC_HDMI_CEC 0xf05
+#define STM32F746_PA15_FUNC_SPI1_NSS_I2S1_WS 0xf06
+#define STM32F746_PA15_FUNC_SPI3_NSS_I2S3_WS 0xf07
+#define STM32F746_PA15_FUNC_UART4_RTS 0xf09
+#define STM32F746_PA15_FUNC_EVENTOUT 0xf10
+#define STM32F746_PA15_FUNC_ANALOG 0xf11
+
+
+#define STM32F746_PB0_FUNC_GPIO 0x1000
+#define STM32F746_PB0_FUNC_TIM1_CH2N 0x1002
+#define STM32F746_PB0_FUNC_TIM3_CH3 0x1003
+#define STM32F746_PB0_FUNC_TIM8_CH2N 0x1004
+#define STM32F746_PB0_FUNC_UART4_CTS 0x1009
+#define STM32F746_PB0_FUNC_LCD_R3 0x100a
+#define STM32F746_PB0_FUNC_OTG_HS_ULPI_D1 0x100b
+#define STM32F746_PB0_FUNC_ETH_MII_RXD2 0x100c
+#define STM32F746_PB0_FUNC_EVENTOUT 0x1010
+#define STM32F746_PB0_FUNC_ANALOG 0x1011
+
+#define STM32F746_PB1_FUNC_GPIO 0x1100
+#define STM32F746_PB1_FUNC_TIM1_CH3N 0x1102
+#define STM32F746_PB1_FUNC_TIM3_CH4 0x1103
+#define STM32F746_PB1_FUNC_TIM8_CH3N 0x1104
+#define STM32F746_PB1_FUNC_LCD_R6 0x110a
+#define STM32F746_PB1_FUNC_OTG_HS_ULPI_D2 0x110b
+#define STM32F746_PB1_FUNC_ETH_MII_RXD3 0x110c
+#define STM32F746_PB1_FUNC_EVENTOUT 0x1110
+#define STM32F746_PB1_FUNC_ANALOG 0x1111
+
+#define STM32F746_PB2_FUNC_GPIO 0x1200
+#define STM32F746_PB2_FUNC_SAI1_SD_A 0x1207
+#define STM32F746_PB2_FUNC_SPI3_MOSI_I2S3_SD 0x1208
+#define STM32F746_PB2_FUNC_QUADSPI_CLK 0x120a
+#define STM32F746_PB2_FUNC_EVENTOUT 0x1210
+#define STM32F746_PB2_FUNC_ANALOG 0x1211
+
+#define STM32F746_PB3_FUNC_GPIO 0x1300
+#define STM32F746_PB3_FUNC_JTDO_TRACESWO 0x1301
+#define STM32F746_PB3_FUNC_TIM2_CH2 0x1302
+#define STM32F746_PB3_FUNC_SPI1_SCK_I2S1_CK 0x1306
+#define STM32F746_PB3_FUNC_SPI3_SCK_I2S3_CK 0x1307
+#define STM32F746_PB3_FUNC_EVENTOUT 0x1310
+#define STM32F746_PB3_FUNC_ANALOG 0x1311
+
+#define STM32F746_PB4_FUNC_GPIO 0x1400
+#define STM32F746_PB4_FUNC_NJTRST 0x1401
+#define STM32F746_PB4_FUNC_TIM3_CH1 0x1403
+#define STM32F746_PB4_FUNC_SPI1_MISO 0x1406
+#define STM32F746_PB4_FUNC_SPI3_MISO 0x1407
+#define STM32F746_PB4_FUNC_SPI2_NSS_I2S2_WS 0x1408
+#define STM32F746_PB4_FUNC_EVENTOUT 0x1410
+#define STM32F746_PB4_FUNC_ANALOG 0x1411
+
+#define STM32F746_PB5_FUNC_GPIO 0x1500
+#define STM32F746_PB5_FUNC_TIM3_CH2 0x1503
+#define STM32F746_PB5_FUNC_I2C1_SMBA 0x1505
+#define STM32F746_PB5_FUNC_SPI1_MOSI_I2S1_SD 0x1506
+#define STM32F746_PB5_FUNC_SPI3_MOSI_I2S3_SD 0x1507
+#define STM32F746_PB5_FUNC_CAN2_RX 0x150a
+#define STM32F746_PB5_FUNC_OTG_HS_ULPI_D7 0x150b
+#define STM32F746_PB5_FUNC_ETH_PPS_OUT 0x150c
+#define STM32F746_PB5_FUNC_FMC_SDCKE1 0x150d
+#define STM32F746_PB5_FUNC_DCMI_D10 0x150e
+#define STM32F746_PB5_FUNC_EVENTOUT 0x1510
+#define STM32F746_PB5_FUNC_ANALOG 0x1511
+
+#define STM32F746_PB6_FUNC_GPIO 0x1600
+#define STM32F746_PB6_FUNC_TIM4_CH1 0x1603
+#define STM32F746_PB6_FUNC_HDMI_CEC 0x1604
+#define STM32F746_PB6_FUNC_I2C1_SCL 0x1605
+#define STM32F746_PB6_FUNC_USART1_TX 0x1608
+#define STM32F746_PB6_FUNC_CAN2_TX 0x160a
+#define STM32F746_PB6_FUNC_QUADSPI_BK1_NCS 0x160b
+#define STM32F746_PB6_FUNC_FMC_SDNE1 0x160d
+#define STM32F746_PB6_FUNC_DCMI_D5 0x160e
+#define STM32F746_PB6_FUNC_EVENTOUT 0x1610
+#define STM32F746_PB6_FUNC_ANALOG 0x1611
+
+#define STM32F746_PB7_FUNC_GPIO 0x1700
+#define STM32F746_PB7_FUNC_TIM4_CH2 0x1703
+#define STM32F746_PB7_FUNC_I2C1_SDA 0x1705
+#define STM32F746_PB7_FUNC_USART1_RX 0x1708
+#define STM32F746_PB7_FUNC_FMC_NL 0x170d
+#define STM32F746_PB7_FUNC_DCMI_VSYNC 0x170e
+#define STM32F746_PB7_FUNC_EVENTOUT 0x1710
+#define STM32F746_PB7_FUNC_ANALOG 0x1711
+
+#define STM32F746_PB8_FUNC_GPIO 0x1800
+#define STM32F746_PB8_FUNC_TIM4_CH3 0x1803
+#define STM32F746_PB8_FUNC_TIM10_CH1 0x1804
+#define STM32F746_PB8_FUNC_I2C1_SCL 0x1805
+#define STM32F746_PB8_FUNC_CAN1_RX 0x180a
+#define STM32F746_PB8_FUNC_ETH_MII_TXD3 0x180c
+#define STM32F746_PB8_FUNC_SDMMC1_D4 0x180d
+#define STM32F746_PB8_FUNC_DCMI_D6 0x180e
+#define STM32F746_PB8_FUNC_LCD_B6 0x180f
+#define STM32F746_PB8_FUNC_EVENTOUT 0x1810
+#define STM32F746_PB8_FUNC_ANALOG 0x1811
+
+#define STM32F746_PB9_FUNC_GPIO 0x1900
+#define STM32F746_PB9_FUNC_TIM4_CH4 0x1903
+#define STM32F746_PB9_FUNC_TIM11_CH1 0x1904
+#define STM32F746_PB9_FUNC_I2C1_SDA 0x1905
+#define STM32F746_PB9_FUNC_SPI2_NSS_I2S2_WS 0x1906
+#define STM32F746_PB9_FUNC_CAN1_TX 0x190a
+#define STM32F746_PB9_FUNC_SDMMC1_D5 0x190d
+#define STM32F746_PB9_FUNC_DCMI_D7 0x190e
+#define STM32F746_PB9_FUNC_LCD_B7 0x190f
+#define STM32F746_PB9_FUNC_EVENTOUT 0x1910
+#define STM32F746_PB9_FUNC_ANALOG 0x1911
+
+#define STM32F746_PB10_FUNC_GPIO 0x1a00
+#define STM32F746_PB10_FUNC_TIM2_CH3 0x1a02
+#define STM32F746_PB10_FUNC_I2C2_SCL 0x1a05
+#define STM32F746_PB10_FUNC_SPI2_SCK_I2S2_CK 0x1a06
+#define STM32F746_PB10_FUNC_USART3_TX 0x1a08
+#define STM32F746_PB10_FUNC_OTG_HS_ULPI_D3 0x1a0b
+#define STM32F746_PB10_FUNC_ETH_MII_RX_ER 0x1a0c
+#define STM32F746_PB10_FUNC_LCD_G4 0x1a0f
+#define STM32F746_PB10_FUNC_EVENTOUT 0x1a10
+#define STM32F746_PB10_FUNC_ANALOG 0x1a11
+
+#define STM32F746_PB11_FUNC_GPIO 0x1b00
+#define STM32F746_PB11_FUNC_TIM2_CH4 0x1b02
+#define STM32F746_PB11_FUNC_I2C2_SDA 0x1b05
+#define STM32F746_PB11_FUNC_USART3_RX 0x1b08
+#define STM32F746_PB11_FUNC_OTG_HS_ULPI_D4 0x1b0b
+#define STM32F746_PB11_FUNC_ETH_MII_TX_EN_ETH_RMII_TX_EN 0x1b0c
+#define STM32F746_PB11_FUNC_LCD_G5 0x1b0f
+#define STM32F746_PB11_FUNC_EVENTOUT 0x1b10
+#define STM32F746_PB11_FUNC_ANALOG 0x1b11
+
+#define STM32F746_PB12_FUNC_GPIO 0x1c00
+#define STM32F746_PB12_FUNC_TIM1_BKIN 0x1c02
+#define STM32F746_PB12_FUNC_I2C2_SMBA 0x1c05
+#define STM32F746_PB12_FUNC_SPI2_NSS_I2S2_WS 0x1c06
+#define STM32F746_PB12_FUNC_USART3_CK 0x1c08
+#define STM32F746_PB12_FUNC_CAN2_RX 0x1c0a
+#define STM32F746_PB12_FUNC_OTG_HS_ULPI_D5 0x1c0b
+#define STM32F746_PB12_FUNC_ETH_MII_TXD0_ETH_RMII_TXD0 0x1c0c
+#define STM32F746_PB12_FUNC_OTG_HS_ID 0x1c0d
+#define STM32F746_PB12_FUNC_EVENTOUT 0x1c10
+#define STM32F746_PB12_FUNC_ANALOG 0x1c11
+
+#define STM32F746_PB13_FUNC_GPIO 0x1d00
+#define STM32F746_PB13_FUNC_TIM1_CH1N 0x1d02
+#define STM32F746_PB13_FUNC_SPI2_SCK_I2S2_CK 0x1d06
+#define STM32F746_PB13_FUNC_USART3_CTS 0x1d08
+#define STM32F746_PB13_FUNC_CAN2_TX 0x1d0a
+#define STM32F746_PB13_FUNC_OTG_HS_ULPI_D6 0x1d0b
+#define STM32F746_PB13_FUNC_ETH_MII_TXD1_ETH_RMII_TXD1 0x1d0c
+#define STM32F746_PB13_FUNC_EVENTOUT 0x1d10
+#define STM32F746_PB13_FUNC_ANALOG 0x1d11
+
+#define STM32F746_PB14_FUNC_GPIO 0x1e00
+#define STM32F746_PB14_FUNC_TIM1_CH2N 0x1e02
+#define STM32F746_PB14_FUNC_TIM8_CH2N 0x1e04
+#define STM32F746_PB14_FUNC_SPI2_MISO 0x1e06
+#define STM32F746_PB14_FUNC_USART3_RTS 0x1e08
+#define STM32F746_PB14_FUNC_TIM12_CH1 0x1e0a
+#define STM32F746_PB14_FUNC_OTG_HS_DM 0x1e0d
+#define STM32F746_PB14_FUNC_EVENTOUT 0x1e10
+#define STM32F746_PB14_FUNC_ANALOG 0x1e11
+
+#define STM32F746_PB15_FUNC_GPIO 0x1f00
+#define STM32F746_PB15_FUNC_RTC_REFIN 0x1f01
+#define STM32F746_PB15_FUNC_TIM1_CH3N 0x1f02
+#define STM32F746_PB15_FUNC_TIM8_CH3N 0x1f04
+#define STM32F746_PB15_FUNC_SPI2_MOSI_I2S2_SD 0x1f06
+#define STM32F746_PB15_FUNC_TIM12_CH2 0x1f0a
+#define STM32F746_PB15_FUNC_OTG_HS_DP 0x1f0d
+#define STM32F746_PB15_FUNC_EVENTOUT 0x1f10
+#define STM32F746_PB15_FUNC_ANALOG 0x1f11
+
+
+#define STM32F746_PC0_FUNC_GPIO 0x2000
+#define STM32F746_PC0_FUNC_SAI2_FS_B 0x2009
+#define STM32F746_PC0_FUNC_OTG_HS_ULPI_STP 0x200b
+#define STM32F746_PC0_FUNC_FMC_SDNWE 0x200d
+#define STM32F746_PC0_FUNC_LCD_R5 0x200f
+#define STM32F746_PC0_FUNC_EVENTOUT 0x2010
+#define STM32F746_PC0_FUNC_ANALOG 0x2011
+
+#define STM32F746_PC1_FUNC_GPIO 0x2100
+#define STM32F746_PC1_FUNC_TRACED0 0x2101
+#define STM32F746_PC1_FUNC_SPI2_MOSI_I2S2_SD 0x2106
+#define STM32F746_PC1_FUNC_SAI1_SD_A 0x2107
+#define STM32F746_PC1_FUNC_ETH_MDC 0x210c
+#define STM32F746_PC1_FUNC_EVENTOUT 0x2110
+#define STM32F746_PC1_FUNC_ANALOG 0x2111
+
+#define STM32F746_PC2_FUNC_GPIO 0x2200
+#define STM32F746_PC2_FUNC_SPI2_MISO 0x2206
+#define STM32F746_PC2_FUNC_OTG_HS_ULPI_DIR 0x220b
+#define STM32F746_PC2_FUNC_ETH_MII_TXD2 0x220c
+#define STM32F746_PC2_FUNC_FMC_SDNE0 0x220d
+#define STM32F746_PC2_FUNC_EVENTOUT 0x2210
+#define STM32F746_PC2_FUNC_ANALOG 0x2211
+
+#define STM32F746_PC3_FUNC_GPIO 0x2300
+#define STM32F746_PC3_FUNC_SPI2_MOSI_I2S2_SD 0x2306
+#define STM32F746_PC3_FUNC_OTG_HS_ULPI_NXT 0x230b
+#define STM32F746_PC3_FUNC_ETH_MII_TX_CLK 0x230c
+#define STM32F746_PC3_FUNC_FMC_SDCKE0 0x230d
+#define STM32F746_PC3_FUNC_EVENTOUT 0x2310
+#define STM32F746_PC3_FUNC_ANALOG 0x2311
+
+#define STM32F746_PC4_FUNC_GPIO 0x2400
+#define STM32F746_PC4_FUNC_I2S1_MCK 0x2406
+#define STM32F746_PC4_FUNC_SPDIFRX_IN2 0x2409
+#define STM32F746_PC4_FUNC_ETH_MII_RXD0_ETH_RMII_RXD0 0x240c
+#define STM32F746_PC4_FUNC_FMC_SDNE0 0x240d
+#define STM32F746_PC4_FUNC_EVENTOUT 0x2410
+#define STM32F746_PC4_FUNC_ANALOG 0x2411
+
+#define STM32F746_PC5_FUNC_GPIO 0x2500
+#define STM32F746_PC5_FUNC_SPDIFRX_IN3 0x2509
+#define STM32F746_PC5_FUNC_ETH_MII_RXD1_ETH_RMII_RXD1 0x250c
+#define STM32F746_PC5_FUNC_FMC_SDCKE0 0x250d
+#define STM32F746_PC5_FUNC_EVENTOUT 0x2510
+#define STM32F746_PC5_FUNC_ANALOG 0x2511
+
+#define STM32F746_PC6_FUNC_GPIO 0x2600
+#define STM32F746_PC6_FUNC_TIM3_CH1 0x2603
+#define STM32F746_PC6_FUNC_TIM8_CH1 0x2604
+#define STM32F746_PC6_FUNC_I2S2_MCK 0x2606
+#define STM32F746_PC6_FUNC_USART6_TX 0x2609
+#define STM32F746_PC6_FUNC_SDMMC1_D6 0x260d
+#define STM32F746_PC6_FUNC_DCMI_D0 0x260e
+#define STM32F746_PC6_FUNC_LCD_HSYNC 0x260f
+#define STM32F746_PC6_FUNC_EVENTOUT 0x2610
+#define STM32F746_PC6_FUNC_ANALOG 0x2611
+
+#define STM32F746_PC7_FUNC_GPIO 0x2700
+#define STM32F746_PC7_FUNC_TIM3_CH2 0x2703
+#define STM32F746_PC7_FUNC_TIM8_CH2 0x2704
+#define STM32F746_PC7_FUNC_I2S3_MCK 0x2707
+#define STM32F746_PC7_FUNC_USART6_RX 0x2709
+#define STM32F746_PC7_FUNC_SDMMC1_D7 0x270d
+#define STM32F746_PC7_FUNC_DCMI_D1 0x270e
+#define STM32F746_PC7_FUNC_LCD_G6 0x270f
+#define STM32F746_PC7_FUNC_EVENTOUT 0x2710
+#define STM32F746_PC7_FUNC_ANALOG 0x2711
+
+#define STM32F746_PC8_FUNC_GPIO 0x2800
+#define STM32F746_PC8_FUNC_TRACED1 0x2801
+#define STM32F746_PC8_FUNC_TIM3_CH3 0x2803
+#define STM32F746_PC8_FUNC_TIM8_CH3 0x2804
+#define STM32F746_PC8_FUNC_UART5_RTS 0x2808
+#define STM32F746_PC8_FUNC_USART6_CK 0x2809
+#define STM32F746_PC8_FUNC_SDMMC1_D0 0x280d
+#define STM32F746_PC8_FUNC_DCMI_D2 0x280e
+#define STM32F746_PC8_FUNC_EVENTOUT 0x2810
+#define STM32F746_PC8_FUNC_ANALOG 0x2811
+
+#define STM32F746_PC9_FUNC_GPIO 0x2900
+#define STM32F746_PC9_FUNC_MCO2 0x2901
+#define STM32F746_PC9_FUNC_TIM3_CH4 0x2903
+#define STM32F746_PC9_FUNC_TIM8_CH4 0x2904
+#define STM32F746_PC9_FUNC_I2C3_SDA 0x2905
+#define STM32F746_PC9_FUNC_I2S_CKIN 0x2906
+#define STM32F746_PC9_FUNC_UART5_CTS 0x2908
+#define STM32F746_PC9_FUNC_QUADSPI_BK1_IO0 0x290a
+#define STM32F746_PC9_FUNC_SDMMC1_D1 0x290d
+#define STM32F746_PC9_FUNC_DCMI_D3 0x290e
+#define STM32F746_PC9_FUNC_EVENTOUT 0x2910
+#define STM32F746_PC9_FUNC_ANALOG 0x2911
+
+#define STM32F746_PC10_FUNC_GPIO 0x2a00
+#define STM32F746_PC10_FUNC_SPI3_SCK_I2S3_CK 0x2a07
+#define STM32F746_PC10_FUNC_USART3_TX 0x2a08
+#define STM32F746_PC10_FUNC_UART4_TX 0x2a09
+#define STM32F746_PC10_FUNC_QUADSPI_BK1_IO1 0x2a0a
+#define STM32F746_PC10_FUNC_SDMMC1_D2 0x2a0d
+#define STM32F746_PC10_FUNC_DCMI_D8 0x2a0e
+#define STM32F746_PC10_FUNC_LCD_R2 0x2a0f
+#define STM32F746_PC10_FUNC_EVENTOUT 0x2a10
+#define STM32F746_PC10_FUNC_ANALOG 0x2a11
+
+#define STM32F746_PC11_FUNC_GPIO 0x2b00
+#define STM32F746_PC11_FUNC_SPI3_MISO 0x2b07
+#define STM32F746_PC11_FUNC_USART3_RX 0x2b08
+#define STM32F746_PC11_FUNC_UART4_RX 0x2b09
+#define STM32F746_PC11_FUNC_QUADSPI_BK2_NCS 0x2b0a
+#define STM32F746_PC11_FUNC_SDMMC1_D3 0x2b0d
+#define STM32F746_PC11_FUNC_DCMI_D4 0x2b0e
+#define STM32F746_PC11_FUNC_EVENTOUT 0x2b10
+#define STM32F746_PC11_FUNC_ANALOG 0x2b11
+
+#define STM32F746_PC12_FUNC_GPIO 0x2c00
+#define STM32F746_PC12_FUNC_TRACED3 0x2c01
+#define STM32F746_PC12_FUNC_SPI3_MOSI_I2S3_SD 0x2c07
+#define STM32F746_PC12_FUNC_USART3_CK 0x2c08
+#define STM32F746_PC12_FUNC_UART5_TX 0x2c09
+#define STM32F746_PC12_FUNC_SDMMC1_CK 0x2c0d
+#define STM32F746_PC12_FUNC_DCMI_D9 0x2c0e
+#define STM32F746_PC12_FUNC_EVENTOUT 0x2c10
+#define STM32F746_PC12_FUNC_ANALOG 0x2c11
+
+#define STM32F746_PC13_FUNC_GPIO 0x2d00
+#define STM32F746_PC13_FUNC_EVENTOUT 0x2d10
+#define STM32F746_PC13_FUNC_ANALOG 0x2d11
+
+#define STM32F746_PC14_FUNC_GPIO 0x2e00
+#define STM32F746_PC14_FUNC_EVENTOUT 0x2e10
+#define STM32F746_PC14_FUNC_ANALOG 0x2e11
+
+#define STM32F746_PC15_FUNC_GPIO 0x2f00
+#define STM32F746_PC15_FUNC_EVENTOUT 0x2f10
+#define STM32F746_PC15_FUNC_ANALOG 0x2f11
+
+
+#define STM32F746_PD0_FUNC_GPIO 0x3000
+#define STM32F746_PD0_FUNC_CAN1_RX 0x300a
+#define STM32F746_PD0_FUNC_FMC_D2 0x300d
+#define STM32F746_PD0_FUNC_EVENTOUT 0x3010
+#define STM32F746_PD0_FUNC_ANALOG 0x3011
+
+#define STM32F746_PD1_FUNC_GPIO 0x3100
+#define STM32F746_PD1_FUNC_CAN1_TX 0x310a
+#define STM32F746_PD1_FUNC_FMC_D3 0x310d
+#define STM32F746_PD1_FUNC_EVENTOUT 0x3110
+#define STM32F746_PD1_FUNC_ANALOG 0x3111
+
+#define STM32F746_PD2_FUNC_GPIO 0x3200
+#define STM32F746_PD2_FUNC_TRACED2 0x3201
+#define STM32F746_PD2_FUNC_TIM3_ETR 0x3203
+#define STM32F746_PD2_FUNC_UART5_RX 0x3209
+#define STM32F746_PD2_FUNC_SDMMC1_CMD 0x320d
+#define STM32F746_PD2_FUNC_DCMI_D11 0x320e
+#define STM32F746_PD2_FUNC_EVENTOUT 0x3210
+#define STM32F746_PD2_FUNC_ANALOG 0x3211
+
+#define STM32F746_PD3_FUNC_GPIO 0x3300
+#define STM32F746_PD3_FUNC_SPI2_SCK_I2S2_CK 0x3306
+#define STM32F746_PD3_FUNC_USART2_CTS 0x3308
+#define STM32F746_PD3_FUNC_FMC_CLK 0x330d
+#define STM32F746_PD3_FUNC_DCMI_D5 0x330e
+#define STM32F746_PD3_FUNC_LCD_G7 0x330f
+#define STM32F746_PD3_FUNC_EVENTOUT 0x3310
+#define STM32F746_PD3_FUNC_ANALOG 0x3311
+
+#define STM32F746_PD4_FUNC_GPIO 0x3400
+#define STM32F746_PD4_FUNC_USART2_RTS 0x3408
+#define STM32F746_PD4_FUNC_FMC_NOE 0x340d
+#define STM32F746_PD4_FUNC_EVENTOUT 0x3410
+#define STM32F746_PD4_FUNC_ANALOG 0x3411
+
+#define STM32F746_PD5_FUNC_GPIO 0x3500
+#define STM32F746_PD5_FUNC_USART2_TX 0x3508
+#define STM32F746_PD5_FUNC_FMC_NWE 0x350d
+#define STM32F746_PD5_FUNC_EVENTOUT 0x3510
+#define STM32F746_PD5_FUNC_ANALOG 0x3511
+
+#define STM32F746_PD6_FUNC_GPIO 0x3600
+#define STM32F746_PD6_FUNC_SPI3_MOSI_I2S3_SD 0x3606
+#define STM32F746_PD6_FUNC_SAI1_SD_A 0x3607
+#define STM32F746_PD6_FUNC_USART2_RX 0x3608
+#define STM32F746_PD6_FUNC_FMC_NWAIT 0x360d
+#define STM32F746_PD6_FUNC_DCMI_D10 0x360e
+#define STM32F746_PD6_FUNC_LCD_B2 0x360f
+#define STM32F746_PD6_FUNC_EVENTOUT 0x3610
+#define STM32F746_PD6_FUNC_ANALOG 0x3611
+
+#define STM32F746_PD7_FUNC_GPIO 0x3700
+#define STM32F746_PD7_FUNC_USART2_CK 0x3708
+#define STM32F746_PD7_FUNC_SPDIFRX_IN0 0x3709
+#define STM32F746_PD7_FUNC_FMC_NE1 0x370d
+#define STM32F746_PD7_FUNC_EVENTOUT 0x3710
+#define STM32F746_PD7_FUNC_ANALOG 0x3711
+
+#define STM32F746_PD8_FUNC_GPIO 0x3800
+#define STM32F746_PD8_FUNC_USART3_TX 0x3808
+#define STM32F746_PD8_FUNC_SPDIFRX_IN1 0x3809
+#define STM32F746_PD8_FUNC_FMC_D13 0x380d
+#define STM32F746_PD8_FUNC_EVENTOUT 0x3810
+#define STM32F746_PD8_FUNC_ANALOG 0x3811
+
+#define STM32F746_PD9_FUNC_GPIO 0x3900
+#define STM32F746_PD9_FUNC_USART3_RX 0x3908
+#define STM32F746_PD9_FUNC_FMC_D14 0x390d
+#define STM32F746_PD9_FUNC_EVENTOUT 0x3910
+#define STM32F746_PD9_FUNC_ANALOG 0x3911
+
+#define STM32F746_PD10_FUNC_GPIO 0x3a00
+#define STM32F746_PD10_FUNC_USART3_CK 0x3a08
+#define STM32F746_PD10_FUNC_FMC_D15 0x3a0d
+#define STM32F746_PD10_FUNC_LCD_B3 0x3a0f
+#define STM32F746_PD10_FUNC_EVENTOUT 0x3a10
+#define STM32F746_PD10_FUNC_ANALOG 0x3a11
+
+#define STM32F746_PD11_FUNC_GPIO 0x3b00
+#define STM32F746_PD11_FUNC_I2C4_SMBA 0x3b05
+#define STM32F746_PD11_FUNC_USART3_CTS 0x3b08
+#define STM32F746_PD11_FUNC_QUADSPI_BK1_IO0 0x3b0a
+#define STM32F746_PD11_FUNC_SAI2_SD_A 0x3b0b
+#define STM32F746_PD11_FUNC_FMC_A16_FMC_CLE 0x3b0d
+#define STM32F746_PD11_FUNC_EVENTOUT 0x3b10
+#define STM32F746_PD11_FUNC_ANALOG 0x3b11
+
+#define STM32F746_PD12_FUNC_GPIO 0x3c00
+#define STM32F746_PD12_FUNC_TIM4_CH1 0x3c03
+#define STM32F746_PD12_FUNC_LPTIM1_IN1 0x3c04
+#define STM32F746_PD12_FUNC_I2C4_SCL 0x3c05
+#define STM32F746_PD12_FUNC_USART3_RTS 0x3c08
+#define STM32F746_PD12_FUNC_QUADSPI_BK1_IO1 0x3c0a
+#define STM32F746_PD12_FUNC_SAI2_FS_A 0x3c0b
+#define STM32F746_PD12_FUNC_FMC_A17_FMC_ALE 0x3c0d
+#define STM32F746_PD12_FUNC_EVENTOUT 0x3c10
+#define STM32F746_PD12_FUNC_ANALOG 0x3c11
+
+#define STM32F746_PD13_FUNC_GPIO 0x3d00
+#define STM32F746_PD13_FUNC_TIM4_CH2 0x3d03
+#define STM32F746_PD13_FUNC_LPTIM1_OUT 0x3d04
+#define STM32F746_PD13_FUNC_I2C4_SDA 0x3d05
+#define STM32F746_PD13_FUNC_QUADSPI_BK1_IO3 0x3d0a
+#define STM32F746_PD13_FUNC_SAI2_SCK_A 0x3d0b
+#define STM32F746_PD13_FUNC_FMC_A18 0x3d0d
+#define STM32F746_PD13_FUNC_EVENTOUT 0x3d10
+#define STM32F746_PD13_FUNC_ANALOG 0x3d11
+
+#define STM32F746_PD14_FUNC_GPIO 0x3e00
+#define STM32F746_PD14_FUNC_TIM4_CH3 0x3e03
+#define STM32F746_PD14_FUNC_UART8_CTS 0x3e09
+#define STM32F746_PD14_FUNC_FMC_D0 0x3e0d
+#define STM32F746_PD14_FUNC_EVENTOUT 0x3e10
+#define STM32F746_PD14_FUNC_ANALOG 0x3e11
+
+#define STM32F746_PD15_FUNC_GPIO 0x3f00
+#define STM32F746_PD15_FUNC_TIM4_CH4 0x3f03
+#define STM32F746_PD15_FUNC_UART8_RTS 0x3f09
+#define STM32F746_PD15_FUNC_FMC_D1 0x3f0d
+#define STM32F746_PD15_FUNC_EVENTOUT 0x3f10
+#define STM32F746_PD15_FUNC_ANALOG 0x3f11
+
+
+#define STM32F746_PE0_FUNC_GPIO 0x4000
+#define STM32F746_PE0_FUNC_TIM4_ETR 0x4003
+#define STM32F746_PE0_FUNC_LPTIM1_ETR 0x4004
+#define STM32F746_PE0_FUNC_UART8_RX 0x4009
+#define STM32F746_PE0_FUNC_SAI2_MCLK_A 0x400b
+#define STM32F746_PE0_FUNC_FMC_NBL0 0x400d
+#define STM32F746_PE0_FUNC_DCMI_D2 0x400e
+#define STM32F746_PE0_FUNC_EVENTOUT 0x4010
+#define STM32F746_PE0_FUNC_ANALOG 0x4011
+
+#define STM32F746_PE1_FUNC_GPIO 0x4100
+#define STM32F746_PE1_FUNC_LPTIM1_IN2 0x4104
+#define STM32F746_PE1_FUNC_UART8_TX 0x4109
+#define STM32F746_PE1_FUNC_FMC_NBL1 0x410d
+#define STM32F746_PE1_FUNC_DCMI_D3 0x410e
+#define STM32F746_PE1_FUNC_EVENTOUT 0x4110
+#define STM32F746_PE1_FUNC_ANALOG 0x4111
+
+#define STM32F746_PE2_FUNC_GPIO 0x4200
+#define STM32F746_PE2_FUNC_TRACECLK 0x4201
+#define STM32F746_PE2_FUNC_SPI4_SCK 0x4206
+#define STM32F746_PE2_FUNC_SAI1_MCLK_A 0x4207
+#define STM32F746_PE2_FUNC_QUADSPI_BK1_IO2 0x420a
+#define STM32F746_PE2_FUNC_ETH_MII_TXD3 0x420c
+#define STM32F746_PE2_FUNC_FMC_A23 0x420d
+#define STM32F746_PE2_FUNC_EVENTOUT 0x4210
+#define STM32F746_PE2_FUNC_ANALOG 0x4211
+
+#define STM32F746_PE3_FUNC_GPIO 0x4300
+#define STM32F746_PE3_FUNC_TRACED0 0x4301
+#define STM32F746_PE3_FUNC_SAI1_SD_B 0x4307
+#define STM32F746_PE3_FUNC_FMC_A19 0x430d
+#define STM32F746_PE3_FUNC_EVENTOUT 0x4310
+#define STM32F746_PE3_FUNC_ANALOG 0x4311
+
+#define STM32F746_PE4_FUNC_GPIO 0x4400
+#define STM32F746_PE4_FUNC_TRACED1 0x4401
+#define STM32F746_PE4_FUNC_SPI4_NSS 0x4406
+#define STM32F746_PE4_FUNC_SAI1_FS_A 0x4407
+#define STM32F746_PE4_FUNC_FMC_A20 0x440d
+#define STM32F746_PE4_FUNC_DCMI_D4 0x440e
+#define STM32F746_PE4_FUNC_LCD_B0 0x440f
+#define STM32F746_PE4_FUNC_EVENTOUT 0x4410
+#define STM32F746_PE4_FUNC_ANALOG 0x4411
+
+#define STM32F746_PE5_FUNC_GPIO 0x4500
+#define STM32F746_PE5_FUNC_TRACED2 0x4501
+#define STM32F746_PE5_FUNC_TIM9_CH1 0x4504
+#define STM32F746_PE5_FUNC_SPI4_MISO 0x4506
+#define STM32F746_PE5_FUNC_SAI1_SCK_A 0x4507
+#define STM32F746_PE5_FUNC_FMC_A21 0x450d
+#define STM32F746_PE5_FUNC_DCMI_D6 0x450e
+#define STM32F746_PE5_FUNC_LCD_G0 0x450f
+#define STM32F746_PE5_FUNC_EVENTOUT 0x4510
+#define STM32F746_PE5_FUNC_ANALOG 0x4511
+
+#define STM32F746_PE6_FUNC_GPIO 0x4600
+#define STM32F746_PE6_FUNC_TRACED3 0x4601
+#define STM32F746_PE6_FUNC_TIM1_BKIN2 0x4602
+#define STM32F746_PE6_FUNC_TIM9_CH2 0x4604
+#define STM32F746_PE6_FUNC_SPI4_MOSI 0x4606
+#define STM32F746_PE6_FUNC_SAI1_SD_A 0x4607
+#define STM32F746_PE6_FUNC_SAI2_MCLK_B 0x460b
+#define STM32F746_PE6_FUNC_FMC_A22 0x460d
+#define STM32F746_PE6_FUNC_DCMI_D7 0x460e
+#define STM32F746_PE6_FUNC_LCD_G1 0x460f
+#define STM32F746_PE6_FUNC_EVENTOUT 0x4610
+#define STM32F746_PE6_FUNC_ANALOG 0x4611
+
+#define STM32F746_PE7_FUNC_GPIO 0x4700
+#define STM32F746_PE7_FUNC_TIM1_ETR 0x4702
+#define STM32F746_PE7_FUNC_UART7_RX 0x4709
+#define STM32F746_PE7_FUNC_QUADSPI_BK2_IO0 0x470b
+#define STM32F746_PE7_FUNC_FMC_D4 0x470d
+#define STM32F746_PE7_FUNC_EVENTOUT 0x4710
+#define STM32F746_PE7_FUNC_ANALOG 0x4711
+
+#define STM32F746_PE8_FUNC_GPIO 0x4800
+#define STM32F746_PE8_FUNC_TIM1_CH1N 0x4802
+#define STM32F746_PE8_FUNC_UART7_TX 0x4809
+#define STM32F746_PE8_FUNC_QUADSPI_BK2_IO1 0x480b
+#define STM32F746_PE8_FUNC_FMC_D5 0x480d
+#define STM32F746_PE8_FUNC_EVENTOUT 0x4810
+#define STM32F746_PE8_FUNC_ANALOG 0x4811
+
+#define STM32F746_PE9_FUNC_GPIO 0x4900
+#define STM32F746_PE9_FUNC_TIM1_CH1 0x4902
+#define STM32F746_PE9_FUNC_UART7_RTS 0x4909
+#define STM32F746_PE9_FUNC_QUADSPI_BK2_IO2 0x490b
+#define STM32F746_PE9_FUNC_FMC_D6 0x490d
+#define STM32F746_PE9_FUNC_EVENTOUT 0x4910
+#define STM32F746_PE9_FUNC_ANALOG 0x4911
+
+#define STM32F746_PE10_FUNC_GPIO 0x4a00
+#define STM32F746_PE10_FUNC_TIM1_CH2N 0x4a02
+#define STM32F746_PE10_FUNC_UART7_CTS 0x4a09
+#define STM32F746_PE10_FUNC_QUADSPI_BK2_IO3 0x4a0b
+#define STM32F746_PE10_FUNC_FMC_D7 0x4a0d
+#define STM32F746_PE10_FUNC_EVENTOUT 0x4a10
+#define STM32F746_PE10_FUNC_ANALOG 0x4a11
+
+#define STM32F746_PE11_FUNC_GPIO 0x4b00
+#define STM32F746_PE11_FUNC_TIM1_CH2 0x4b02
+#define STM32F746_PE11_FUNC_SPI4_NSS 0x4b06
+#define STM32F746_PE11_FUNC_SAI2_SD_B 0x4b0b
+#define STM32F746_PE11_FUNC_FMC_D8 0x4b0d
+#define STM32F746_PE11_FUNC_LCD_G3 0x4b0f
+#define STM32F746_PE11_FUNC_EVENTOUT 0x4b10
+#define STM32F746_PE11_FUNC_ANALOG 0x4b11
+
+#define STM32F746_PE12_FUNC_GPIO 0x4c00
+#define STM32F746_PE12_FUNC_TIM1_CH3N 0x4c02
+#define STM32F746_PE12_FUNC_SPI4_SCK 0x4c06
+#define STM32F746_PE12_FUNC_SAI2_SCK_B 0x4c0b
+#define STM32F746_PE12_FUNC_FMC_D9 0x4c0d
+#define STM32F746_PE12_FUNC_LCD_B4 0x4c0f
+#define STM32F746_PE12_FUNC_EVENTOUT 0x4c10
+#define STM32F746_PE12_FUNC_ANALOG 0x4c11
+
+#define STM32F746_PE13_FUNC_GPIO 0x4d00
+#define STM32F746_PE13_FUNC_TIM1_CH3 0x4d02
+#define STM32F746_PE13_FUNC_SPI4_MISO 0x4d06
+#define STM32F746_PE13_FUNC_SAI2_FS_B 0x4d0b
+#define STM32F746_PE13_FUNC_FMC_D10 0x4d0d
+#define STM32F746_PE13_FUNC_LCD_DE 0x4d0f
+#define STM32F746_PE13_FUNC_EVENTOUT 0x4d10
+#define STM32F746_PE13_FUNC_ANALOG 0x4d11
+
+#define STM32F746_PE14_FUNC_GPIO 0x4e00
+#define STM32F746_PE14_FUNC_TIM1_CH4 0x4e02
+#define STM32F746_PE14_FUNC_SPI4_MOSI 0x4e06
+#define STM32F746_PE14_FUNC_SAI2_MCLK_B 0x4e0b
+#define STM32F746_PE14_FUNC_FMC_D11 0x4e0d
+#define STM32F746_PE14_FUNC_LCD_CLK 0x4e0f
+#define STM32F746_PE14_FUNC_EVENTOUT 0x4e10
+#define STM32F746_PE14_FUNC_ANALOG 0x4e11
+
+#define STM32F746_PE15_FUNC_GPIO 0x4f00
+#define STM32F746_PE15_FUNC_TIM1_BKIN 0x4f02
+#define STM32F746_PE15_FUNC_FMC_D12 0x4f0d
+#define STM32F746_PE15_FUNC_LCD_R7 0x4f0f
+#define STM32F746_PE15_FUNC_EVENTOUT 0x4f10
+#define STM32F746_PE15_FUNC_ANALOG 0x4f11
+
+
+#define STM32F746_PF0_FUNC_GPIO 0x5000
+#define STM32F746_PF0_FUNC_I2C2_SDA 0x5005
+#define STM32F746_PF0_FUNC_FMC_A0 0x500d
+#define STM32F746_PF0_FUNC_EVENTOUT 0x5010
+#define STM32F746_PF0_FUNC_ANALOG 0x5011
+
+#define STM32F746_PF1_FUNC_GPIO 0x5100
+#define STM32F746_PF1_FUNC_I2C2_SCL 0x5105
+#define STM32F746_PF1_FUNC_FMC_A1 0x510d
+#define STM32F746_PF1_FUNC_EVENTOUT 0x5110
+#define STM32F746_PF1_FUNC_ANALOG 0x5111
+
+#define STM32F746_PF2_FUNC_GPIO 0x5200
+#define STM32F746_PF2_FUNC_I2C2_SMBA 0x5205
+#define STM32F746_PF2_FUNC_FMC_A2 0x520d
+#define STM32F746_PF2_FUNC_EVENTOUT 0x5210
+#define STM32F746_PF2_FUNC_ANALOG 0x5211
+
+#define STM32F746_PF3_FUNC_GPIO 0x5300
+#define STM32F746_PF3_FUNC_FMC_A3 0x530d
+#define STM32F746_PF3_FUNC_EVENTOUT 0x5310
+#define STM32F746_PF3_FUNC_ANALOG 0x5311
+
+#define STM32F746_PF4_FUNC_GPIO 0x5400
+#define STM32F746_PF4_FUNC_FMC_A4 0x540d
+#define STM32F746_PF4_FUNC_EVENTOUT 0x5410
+#define STM32F746_PF4_FUNC_ANALOG 0x5411
+
+#define STM32F746_PF5_FUNC_GPIO 0x5500
+#define STM32F746_PF5_FUNC_FMC_A5 0x550d
+#define STM32F746_PF5_FUNC_EVENTOUT 0x5510
+#define STM32F746_PF5_FUNC_ANALOG 0x5511
+
+#define STM32F746_PF6_FUNC_GPIO 0x5600
+#define STM32F746_PF6_FUNC_TIM10_CH1 0x5604
+#define STM32F746_PF6_FUNC_SPI5_NSS 0x5606
+#define STM32F746_PF6_FUNC_SAI1_SD_B 0x5607
+#define STM32F746_PF6_FUNC_UART7_RX 0x5609
+#define STM32F746_PF6_FUNC_QUADSPI_BK1_IO3 0x560a
+#define STM32F746_PF6_FUNC_EVENTOUT 0x5610
+#define STM32F746_PF6_FUNC_ANALOG 0x5611
+
+#define STM32F746_PF7_FUNC_GPIO 0x5700
+#define STM32F746_PF7_FUNC_TIM11_CH1 0x5704
+#define STM32F746_PF7_FUNC_SPI5_SCK 0x5706
+#define STM32F746_PF7_FUNC_SAI1_MCLK_B 0x5707
+#define STM32F746_PF7_FUNC_UART7_TX 0x5709
+#define STM32F746_PF7_FUNC_QUADSPI_BK1_IO2 0x570a
+#define STM32F746_PF7_FUNC_EVENTOUT 0x5710
+#define STM32F746_PF7_FUNC_ANALOG 0x5711
+
+#define STM32F746_PF8_FUNC_GPIO 0x5800
+#define STM32F746_PF8_FUNC_SPI5_MISO 0x5806
+#define STM32F746_PF8_FUNC_SAI1_SCK_B 0x5807
+#define STM32F746_PF8_FUNC_UART7_RTS 0x5809
+#define STM32F746_PF8_FUNC_TIM13_CH1 0x580a
+#define STM32F746_PF8_FUNC_QUADSPI_BK1_IO0 0x580b
+#define STM32F746_PF8_FUNC_EVENTOUT 0x5810
+#define STM32F746_PF8_FUNC_ANALOG 0x5811
+
+#define STM32F746_PF9_FUNC_GPIO 0x5900
+#define STM32F746_PF9_FUNC_SPI5_MOSI 0x5906
+#define STM32F746_PF9_FUNC_SAI1_FS_B 0x5907
+#define STM32F746_PF9_FUNC_UART7_CTS 0x5909
+#define STM32F746_PF9_FUNC_TIM14_CH1 0x590a
+#define STM32F746_PF9_FUNC_QUADSPI_BK1_IO1 0x590b
+#define STM32F746_PF9_FUNC_EVENTOUT 0x5910
+#define STM32F746_PF9_FUNC_ANALOG 0x5911
+
+#define STM32F746_PF10_FUNC_GPIO 0x5a00
+#define STM32F746_PF10_FUNC_DCMI_D11 0x5a0e
+#define STM32F746_PF10_FUNC_LCD_DE 0x5a0f
+#define STM32F746_PF10_FUNC_EVENTOUT 0x5a10
+#define STM32F746_PF10_FUNC_ANALOG 0x5a11
+
+#define STM32F746_PF11_FUNC_GPIO 0x5b00
+#define STM32F746_PF11_FUNC_SPI5_MOSI 0x5b06
+#define STM32F746_PF11_FUNC_SAI2_SD_B 0x5b0b
+#define STM32F746_PF11_FUNC_FMC_SDNRAS 0x5b0d
+#define STM32F746_PF11_FUNC_DCMI_D12 0x5b0e
+#define STM32F746_PF11_FUNC_EVENTOUT 0x5b10
+#define STM32F746_PF11_FUNC_ANALOG 0x5b11
+
+#define STM32F746_PF12_FUNC_GPIO 0x5c00
+#define STM32F746_PF12_FUNC_FMC_A6 0x5c0d
+#define STM32F746_PF12_FUNC_EVENTOUT 0x5c10
+#define STM32F746_PF12_FUNC_ANALOG 0x5c11
+
+#define STM32F746_PF13_FUNC_GPIO 0x5d00
+#define STM32F746_PF13_FUNC_I2C4_SMBA 0x5d05
+#define STM32F746_PF13_FUNC_FMC_A7 0x5d0d
+#define STM32F746_PF13_FUNC_EVENTOUT 0x5d10
+#define STM32F746_PF13_FUNC_ANALOG 0x5d11
+
+#define STM32F746_PF14_FUNC_GPIO 0x5e00
+#define STM32F746_PF14_FUNC_I2C4_SCL 0x5e05
+#define STM32F746_PF14_FUNC_FMC_A8 0x5e0d
+#define STM32F746_PF14_FUNC_EVENTOUT 0x5e10
+#define STM32F746_PF14_FUNC_ANALOG 0x5e11
+
+#define STM32F746_PF15_FUNC_GPIO 0x5f00
+#define STM32F746_PF15_FUNC_I2C4_SDA 0x5f05
+#define STM32F746_PF15_FUNC_FMC_A9 0x5f0d
+#define STM32F746_PF15_FUNC_EVENTOUT 0x5f10
+#define STM32F746_PF15_FUNC_ANALOG 0x5f11
+
+
+#define STM32F746_PG0_FUNC_GPIO 0x6000
+#define STM32F746_PG0_FUNC_FMC_A10 0x600d
+#define STM32F746_PG0_FUNC_EVENTOUT 0x6010
+#define STM32F746_PG0_FUNC_ANALOG 0x6011
+
+#define STM32F746_PG1_FUNC_GPIO 0x6100
+#define STM32F746_PG1_FUNC_FMC_A11 0x610d
+#define STM32F746_PG1_FUNC_EVENTOUT 0x6110
+#define STM32F746_PG1_FUNC_ANALOG 0x6111
+
+#define STM32F746_PG2_FUNC_GPIO 0x6200
+#define STM32F746_PG2_FUNC_FMC_A12 0x620d
+#define STM32F746_PG2_FUNC_EVENTOUT 0x6210
+#define STM32F746_PG2_FUNC_ANALOG 0x6211
+
+#define STM32F746_PG3_FUNC_GPIO 0x6300
+#define STM32F746_PG3_FUNC_FMC_A13 0x630d
+#define STM32F746_PG3_FUNC_EVENTOUT 0x6310
+#define STM32F746_PG3_FUNC_ANALOG 0x6311
+
+#define STM32F746_PG4_FUNC_GPIO 0x6400
+#define STM32F746_PG4_FUNC_FMC_A14_FMC_BA0 0x640d
+#define STM32F746_PG4_FUNC_EVENTOUT 0x6410
+#define STM32F746_PG4_FUNC_ANALOG 0x6411
+
+#define STM32F746_PG5_FUNC_GPIO 0x6500
+#define STM32F746_PG5_FUNC_FMC_A15_FMC_BA1 0x650d
+#define STM32F746_PG5_FUNC_EVENTOUT 0x6510
+#define STM32F746_PG5_FUNC_ANALOG 0x6511
+
+#define STM32F746_PG6_FUNC_GPIO 0x6600
+#define STM32F746_PG6_FUNC_DCMI_D12 0x660e
+#define STM32F746_PG6_FUNC_LCD_R7 0x660f
+#define STM32F746_PG6_FUNC_EVENTOUT 0x6610
+#define STM32F746_PG6_FUNC_ANALOG 0x6611
+
+#define STM32F746_PG7_FUNC_GPIO 0x6700
+#define STM32F746_PG7_FUNC_USART6_CK 0x6709
+#define STM32F746_PG7_FUNC_FMC_INT 0x670d
+#define STM32F746_PG7_FUNC_DCMI_D13 0x670e
+#define STM32F746_PG7_FUNC_LCD_CLK 0x670f
+#define STM32F746_PG7_FUNC_EVENTOUT 0x6710
+#define STM32F746_PG7_FUNC_ANALOG 0x6711
+
+#define STM32F746_PG8_FUNC_GPIO 0x6800
+#define STM32F746_PG8_FUNC_SPI6_NSS 0x6806
+#define STM32F746_PG8_FUNC_SPDIFRX_IN2 0x6808
+#define STM32F746_PG8_FUNC_USART6_RTS 0x6809
+#define STM32F746_PG8_FUNC_ETH_PPS_OUT 0x680c
+#define STM32F746_PG8_FUNC_FMC_SDCLK 0x680d
+#define STM32F746_PG8_FUNC_EVENTOUT 0x6810
+#define STM32F746_PG8_FUNC_ANALOG 0x6811
+
+#define STM32F746_PG9_FUNC_GPIO 0x6900
+#define STM32F746_PG9_FUNC_SPDIFRX_IN3 0x6908
+#define STM32F746_PG9_FUNC_USART6_RX 0x6909
+#define STM32F746_PG9_FUNC_QUADSPI_BK2_IO2 0x690a
+#define STM32F746_PG9_FUNC_SAI2_FS_B 0x690b
+#define STM32F746_PG9_FUNC_FMC_NE2_FMC_NCE 0x690d
+#define STM32F746_PG9_FUNC_DCMI_VSYNC 0x690e
+#define STM32F746_PG9_FUNC_EVENTOUT 0x6910
+#define STM32F746_PG9_FUNC_ANALOG 0x6911
+
+#define STM32F746_PG10_FUNC_GPIO 0x6a00
+#define STM32F746_PG10_FUNC_LCD_G3 0x6a0a
+#define STM32F746_PG10_FUNC_SAI2_SD_B 0x6a0b
+#define STM32F746_PG10_FUNC_FMC_NE3 0x6a0d
+#define STM32F746_PG10_FUNC_DCMI_D2 0x6a0e
+#define STM32F746_PG10_FUNC_LCD_B2 0x6a0f
+#define STM32F746_PG10_FUNC_EVENTOUT 0x6a10
+#define STM32F746_PG10_FUNC_ANALOG 0x6a11
+
+#define STM32F746_PG11_FUNC_GPIO 0x6b00
+#define STM32F746_PG11_FUNC_SPDIFRX_IN0 0x6b08
+#define STM32F746_PG11_FUNC_ETH_MII_TX_EN_ETH_RMII_TX_EN 0x6b0c
+#define STM32F746_PG11_FUNC_DCMI_D3 0x6b0e
+#define STM32F746_PG11_FUNC_LCD_B3 0x6b0f
+#define STM32F746_PG11_FUNC_EVENTOUT 0x6b10
+#define STM32F746_PG11_FUNC_ANALOG 0x6b11
+
+#define STM32F746_PG12_FUNC_GPIO 0x6c00
+#define STM32F746_PG12_FUNC_LPTIM1_IN1 0x6c04
+#define STM32F746_PG12_FUNC_SPI6_MISO 0x6c06
+#define STM32F746_PG12_FUNC_SPDIFRX_IN1 0x6c08
+#define STM32F746_PG12_FUNC_USART6_RTS 0x6c09
+#define STM32F746_PG12_FUNC_LCD_B4 0x6c0a
+#define STM32F746_PG12_FUNC_FMC_NE4 0x6c0d
+#define STM32F746_PG12_FUNC_LCD_B1 0x6c0f
+#define STM32F746_PG12_FUNC_EVENTOUT 0x6c10
+#define STM32F746_PG12_FUNC_ANALOG 0x6c11
+
+#define STM32F746_PG13_FUNC_GPIO 0x6d00
+#define STM32F746_PG13_FUNC_TRACED0 0x6d01
+#define STM32F746_PG13_FUNC_LPTIM1_OUT 0x6d04
+#define STM32F746_PG13_FUNC_SPI6_SCK 0x6d06
+#define STM32F746_PG13_FUNC_USART6_CTS 0x6d09
+#define STM32F746_PG13_FUNC_ETH_MII_TXD0_ETH_RMII_TXD0 0x6d0c
+#define STM32F746_PG13_FUNC_FMC_A24 0x6d0d
+#define STM32F746_PG13_FUNC_LCD_R0 0x6d0f
+#define STM32F746_PG13_FUNC_EVENTOUT 0x6d10
+#define STM32F746_PG13_FUNC_ANALOG 0x6d11
+
+#define STM32F746_PG14_FUNC_GPIO 0x6e00
+#define STM32F746_PG14_FUNC_TRACED1 0x6e01
+#define STM32F746_PG14_FUNC_LPTIM1_ETR 0x6e04
+#define STM32F746_PG14_FUNC_SPI6_MOSI 0x6e06
+#define STM32F746_PG14_FUNC_USART6_TX 0x6e09
+#define STM32F746_PG14_FUNC_QUADSPI_BK2_IO3 0x6e0a
+#define STM32F746_PG14_FUNC_ETH_MII_TXD1_ETH_RMII_TXD1 0x6e0c
+#define STM32F746_PG14_FUNC_FMC_A25 0x6e0d
+#define STM32F746_PG14_FUNC_LCD_B0 0x6e0f
+#define STM32F746_PG14_FUNC_EVENTOUT 0x6e10
+#define STM32F746_PG14_FUNC_ANALOG 0x6e11
+
+#define STM32F746_PG15_FUNC_GPIO 0x6f00
+#define STM32F746_PG15_FUNC_USART6_CTS 0x6f09
+#define STM32F746_PG15_FUNC_FMC_SDNCAS 0x6f0d
+#define STM32F746_PG15_FUNC_DCMI_D13 0x6f0e
+#define STM32F746_PG15_FUNC_EVENTOUT 0x6f10
+#define STM32F746_PG15_FUNC_ANALOG 0x6f11
+
+
+#define STM32F746_PH0_FUNC_GPIO 0x7000
+#define STM32F746_PH0_FUNC_EVENTOUT 0x7010
+#define STM32F746_PH0_FUNC_ANALOG 0x7011
+
+#define STM32F746_PH1_FUNC_GPIO 0x7100
+#define STM32F746_PH1_FUNC_EVENTOUT 0x7110
+#define STM32F746_PH1_FUNC_ANALOG 0x7111
+
+#define STM32F746_PH2_FUNC_GPIO 0x7200
+#define STM32F746_PH2_FUNC_LPTIM1_IN2 0x7204
+#define STM32F746_PH2_FUNC_QUADSPI_BK2_IO0 0x720a
+#define STM32F746_PH2_FUNC_SAI2_SCK_B 0x720b
+#define STM32F746_PH2_FUNC_ETH_MII_CRS 0x720c
+#define STM32F746_PH2_FUNC_FMC_SDCKE0 0x720d
+#define STM32F746_PH2_FUNC_LCD_R0 0x720f
+#define STM32F746_PH2_FUNC_EVENTOUT 0x7210
+#define STM32F746_PH2_FUNC_ANALOG 0x7211
+
+#define STM32F746_PH3_FUNC_GPIO 0x7300
+#define STM32F746_PH3_FUNC_QUADSPI_BK2_IO1 0x730a
+#define STM32F746_PH3_FUNC_SAI2_MCLK_B 0x730b
+#define STM32F746_PH3_FUNC_ETH_MII_COL 0x730c
+#define STM32F746_PH3_FUNC_FMC_SDNE0 0x730d
+#define STM32F746_PH3_FUNC_LCD_R1 0x730f
+#define STM32F746_PH3_FUNC_EVENTOUT 0x7310
+#define STM32F746_PH3_FUNC_ANALOG 0x7311
+
+#define STM32F746_PH4_FUNC_GPIO 0x7400
+#define STM32F746_PH4_FUNC_I2C2_SCL 0x7405
+#define STM32F746_PH4_FUNC_OTG_HS_ULPI_NXT 0x740b
+#define STM32F746_PH4_FUNC_EVENTOUT 0x7410
+#define STM32F746_PH4_FUNC_ANALOG 0x7411
+
+#define STM32F746_PH5_FUNC_GPIO 0x7500
+#define STM32F746_PH5_FUNC_I2C2_SDA 0x7505
+#define STM32F746_PH5_FUNC_SPI5_NSS 0x7506
+#define STM32F746_PH5_FUNC_FMC_SDNWE 0x750d
+#define STM32F746_PH5_FUNC_EVENTOUT 0x7510
+#define STM32F746_PH5_FUNC_ANALOG 0x7511
+
+#define STM32F746_PH6_FUNC_GPIO 0x7600
+#define STM32F746_PH6_FUNC_I2C2_SMBA 0x7605
+#define STM32F746_PH6_FUNC_SPI5_SCK 0x7606
+#define STM32F746_PH6_FUNC_TIM12_CH1 0x760a
+#define STM32F746_PH6_FUNC_ETH_MII_RXD2 0x760c
+#define STM32F746_PH6_FUNC_FMC_SDNE1 0x760d
+#define STM32F746_PH6_FUNC_DCMI_D8 0x760e
+#define STM32F746_PH6_FUNC_EVENTOUT 0x7610
+#define STM32F746_PH6_FUNC_ANALOG 0x7611
+
+#define STM32F746_PH7_FUNC_GPIO 0x7700
+#define STM32F746_PH7_FUNC_I2C3_SCL 0x7705
+#define STM32F746_PH7_FUNC_SPI5_MISO 0x7706
+#define STM32F746_PH7_FUNC_ETH_MII_RXD3 0x770c
+#define STM32F746_PH7_FUNC_FMC_SDCKE1 0x770d
+#define STM32F746_PH7_FUNC_DCMI_D9 0x770e
+#define STM32F746_PH7_FUNC_EVENTOUT 0x7710
+#define STM32F746_PH7_FUNC_ANALOG 0x7711
+
+#define STM32F746_PH8_FUNC_GPIO 0x7800
+#define STM32F746_PH8_FUNC_I2C3_SDA 0x7805
+#define STM32F746_PH8_FUNC_FMC_D16 0x780d
+#define STM32F746_PH8_FUNC_DCMI_HSYNC 0x780e
+#define STM32F746_PH8_FUNC_LCD_R2 0x780f
+#define STM32F746_PH8_FUNC_EVENTOUT 0x7810
+#define STM32F746_PH8_FUNC_ANALOG 0x7811
+
+#define STM32F746_PH9_FUNC_GPIO 0x7900
+#define STM32F746_PH9_FUNC_I2C3_SMBA 0x7905
+#define STM32F746_PH9_FUNC_TIM12_CH2 0x790a
+#define STM32F746_PH9_FUNC_FMC_D17 0x790d
+#define STM32F746_PH9_FUNC_DCMI_D0 0x790e
+#define STM32F746_PH9_FUNC_LCD_R3 0x790f
+#define STM32F746_PH9_FUNC_EVENTOUT 0x7910
+#define STM32F746_PH9_FUNC_ANALOG 0x7911
+
+#define STM32F746_PH10_FUNC_GPIO 0x7a00
+#define STM32F746_PH10_FUNC_TIM5_CH1 0x7a03
+#define STM32F746_PH10_FUNC_I2C4_SMBA 0x7a05
+#define STM32F746_PH10_FUNC_FMC_D18 0x7a0d
+#define STM32F746_PH10_FUNC_DCMI_D1 0x7a0e
+#define STM32F746_PH10_FUNC_LCD_R4 0x7a0f
+#define STM32F746_PH10_FUNC_EVENTOUT 0x7a10
+#define STM32F746_PH10_FUNC_ANALOG 0x7a11
+
+#define STM32F746_PH11_FUNC_GPIO 0x7b00
+#define STM32F746_PH11_FUNC_TIM5_CH2 0x7b03
+#define STM32F746_PH11_FUNC_I2C4_SCL 0x7b05
+#define STM32F746_PH11_FUNC_FMC_D19 0x7b0d
+#define STM32F746_PH11_FUNC_DCMI_D2 0x7b0e
+#define STM32F746_PH11_FUNC_LCD_R5 0x7b0f
+#define STM32F746_PH11_FUNC_EVENTOUT 0x7b10
+#define STM32F746_PH11_FUNC_ANALOG 0x7b11
+
+#define STM32F746_PH12_FUNC_GPIO 0x7c00
+#define STM32F746_PH12_FUNC_TIM5_CH3 0x7c03
+#define STM32F746_PH12_FUNC_I2C4_SDA 0x7c05
+#define STM32F746_PH12_FUNC_FMC_D20 0x7c0d
+#define STM32F746_PH12_FUNC_DCMI_D3 0x7c0e
+#define STM32F746_PH12_FUNC_LCD_R6 0x7c0f
+#define STM32F746_PH12_FUNC_EVENTOUT 0x7c10
+#define STM32F746_PH12_FUNC_ANALOG 0x7c11
+
+#define STM32F746_PH13_FUNC_GPIO 0x7d00
+#define STM32F746_PH13_FUNC_TIM8_CH1N 0x7d04
+#define STM32F746_PH13_FUNC_CAN1_TX 0x7d0a
+#define STM32F746_PH13_FUNC_FMC_D21 0x7d0d
+#define STM32F746_PH13_FUNC_LCD_G2 0x7d0f
+#define STM32F746_PH13_FUNC_EVENTOUT 0x7d10
+#define STM32F746_PH13_FUNC_ANALOG 0x7d11
+
+#define STM32F746_PH14_FUNC_GPIO 0x7e00
+#define STM32F746_PH14_FUNC_TIM8_CH2N 0x7e04
+#define STM32F746_PH14_FUNC_FMC_D22 0x7e0d
+#define STM32F746_PH14_FUNC_DCMI_D4 0x7e0e
+#define STM32F746_PH14_FUNC_LCD_G3 0x7e0f
+#define STM32F746_PH14_FUNC_EVENTOUT 0x7e10
+#define STM32F746_PH14_FUNC_ANALOG 0x7e11
+
+#define STM32F746_PH15_FUNC_GPIO 0x7f00
+#define STM32F746_PH15_FUNC_TIM8_CH3N 0x7f04
+#define STM32F746_PH15_FUNC_FMC_D23 0x7f0d
+#define STM32F746_PH15_FUNC_DCMI_D11 0x7f0e
+#define STM32F746_PH15_FUNC_LCD_G4 0x7f0f
+#define STM32F746_PH15_FUNC_EVENTOUT 0x7f10
+#define STM32F746_PH15_FUNC_ANALOG 0x7f11
+
+
+#define STM32F746_PI0_FUNC_GPIO 0x8000
+#define STM32F746_PI0_FUNC_TIM5_CH4 0x8003
+#define STM32F746_PI0_FUNC_SPI2_NSS_I2S2_WS 0x8006
+#define STM32F746_PI0_FUNC_FMC_D24 0x800d
+#define STM32F746_PI0_FUNC_DCMI_D13 0x800e
+#define STM32F746_PI0_FUNC_LCD_G5 0x800f
+#define STM32F746_PI0_FUNC_EVENTOUT 0x8010
+#define STM32F746_PI0_FUNC_ANALOG 0x8011
+
+#define STM32F746_PI1_FUNC_GPIO 0x8100
+#define STM32F746_PI1_FUNC_TIM8_BKIN2 0x8104
+#define STM32F746_PI1_FUNC_SPI2_SCK_I2S2_CK 0x8106
+#define STM32F746_PI1_FUNC_FMC_D25 0x810d
+#define STM32F746_PI1_FUNC_DCMI_D8 0x810e
+#define STM32F746_PI1_FUNC_LCD_G6 0x810f
+#define STM32F746_PI1_FUNC_EVENTOUT 0x8110
+#define STM32F746_PI1_FUNC_ANALOG 0x8111
+
+#define STM32F746_PI2_FUNC_GPIO 0x8200
+#define STM32F746_PI2_FUNC_TIM8_CH4 0x8204
+#define STM32F746_PI2_FUNC_SPI2_MISO 0x8206
+#define STM32F746_PI2_FUNC_FMC_D26 0x820d
+#define STM32F746_PI2_FUNC_DCMI_D9 0x820e
+#define STM32F746_PI2_FUNC_LCD_G7 0x820f
+#define STM32F746_PI2_FUNC_EVENTOUT 0x8210
+#define STM32F746_PI2_FUNC_ANALOG 0x8211
+
+#define STM32F746_PI3_FUNC_GPIO 0x8300
+#define STM32F746_PI3_FUNC_TIM8_ETR 0x8304
+#define STM32F746_PI3_FUNC_SPI2_MOSI_I2S2_SD 0x8306
+#define STM32F746_PI3_FUNC_FMC_D27 0x830d
+#define STM32F746_PI3_FUNC_DCMI_D10 0x830e
+#define STM32F746_PI3_FUNC_EVENTOUT 0x8310
+#define STM32F746_PI3_FUNC_ANALOG 0x8311
+
+#define STM32F746_PI4_FUNC_GPIO 0x8400
+#define STM32F746_PI4_FUNC_TIM8_BKIN 0x8404
+#define STM32F746_PI4_FUNC_SAI2_MCLK_A 0x840b
+#define STM32F746_PI4_FUNC_FMC_NBL2 0x840d
+#define STM32F746_PI4_FUNC_DCMI_D5 0x840e
+#define STM32F746_PI4_FUNC_LCD_B4 0x840f
+#define STM32F746_PI4_FUNC_EVENTOUT 0x8410
+#define STM32F746_PI4_FUNC_ANALOG 0x8411
+
+#define STM32F746_PI5_FUNC_GPIO 0x8500
+#define STM32F746_PI5_FUNC_TIM8_CH1 0x8504
+#define STM32F746_PI5_FUNC_SAI2_SCK_A 0x850b
+#define STM32F746_PI5_FUNC_FMC_NBL3 0x850d
+#define STM32F746_PI5_FUNC_DCMI_VSYNC 0x850e
+#define STM32F746_PI5_FUNC_LCD_B5 0x850f
+#define STM32F746_PI5_FUNC_EVENTOUT 0x8510
+#define STM32F746_PI5_FUNC_ANALOG 0x8511
+
+#define STM32F746_PI6_FUNC_GPIO 0x8600
+#define STM32F746_PI6_FUNC_TIM8_CH2 0x8604
+#define STM32F746_PI6_FUNC_SAI2_SD_A 0x860b
+#define STM32F746_PI6_FUNC_FMC_D28 0x860d
+#define STM32F746_PI6_FUNC_DCMI_D6 0x860e
+#define STM32F746_PI6_FUNC_LCD_B6 0x860f
+#define STM32F746_PI6_FUNC_EVENTOUT 0x8610
+#define STM32F746_PI6_FUNC_ANALOG 0x8611
+
+#define STM32F746_PI7_FUNC_GPIO 0x8700
+#define STM32F746_PI7_FUNC_TIM8_CH3 0x8704
+#define STM32F746_PI7_FUNC_SAI2_FS_A 0x870b
+#define STM32F746_PI7_FUNC_FMC_D29 0x870d
+#define STM32F746_PI7_FUNC_DCMI_D7 0x870e
+#define STM32F746_PI7_FUNC_LCD_B7 0x870f
+#define STM32F746_PI7_FUNC_EVENTOUT 0x8710
+#define STM32F746_PI7_FUNC_ANALOG 0x8711
+
+#define STM32F746_PI8_FUNC_GPIO 0x8800
+#define STM32F746_PI8_FUNC_EVENTOUT 0x8810
+#define STM32F746_PI8_FUNC_ANALOG 0x8811
+
+#define STM32F746_PI9_FUNC_GPIO 0x8900
+#define STM32F746_PI9_FUNC_CAN1_RX 0x890a
+#define STM32F746_PI9_FUNC_FMC_D30 0x890d
+#define STM32F746_PI9_FUNC_LCD_VSYNC 0x890f
+#define STM32F746_PI9_FUNC_EVENTOUT 0x8910
+#define STM32F746_PI9_FUNC_ANALOG 0x8911
+
+#define STM32F746_PI10_FUNC_GPIO 0x8a00
+#define STM32F746_PI10_FUNC_ETH_MII_RX_ER 0x8a0c
+#define STM32F746_PI10_FUNC_FMC_D31 0x8a0d
+#define STM32F746_PI10_FUNC_LCD_HSYNC 0x8a0f
+#define STM32F746_PI10_FUNC_EVENTOUT 0x8a10
+#define STM32F746_PI10_FUNC_ANALOG 0x8a11
+
+#define STM32F746_PI11_FUNC_GPIO 0x8b00
+#define STM32F746_PI11_FUNC_OTG_HS_ULPI_DIR 0x8b0b
+#define STM32F746_PI11_FUNC_EVENTOUT 0x8b10
+#define STM32F746_PI11_FUNC_ANALOG 0x8b11
+
+#define STM32F746_PI12_FUNC_GPIO 0x8c00
+#define STM32F746_PI12_FUNC_LCD_HSYNC 0x8c0f
+#define STM32F746_PI12_FUNC_EVENTOUT 0x8c10
+#define STM32F746_PI12_FUNC_ANALOG 0x8c11
+
+#define STM32F746_PI13_FUNC_GPIO 0x8d00
+#define STM32F746_PI13_FUNC_LCD_VSYNC 0x8d0f
+#define STM32F746_PI13_FUNC_EVENTOUT 0x8d10
+#define STM32F746_PI13_FUNC_ANALOG 0x8d11
+
+#define STM32F746_PI14_FUNC_GPIO 0x8e00
+#define STM32F746_PI14_FUNC_LCD_CLK 0x8e0f
+#define STM32F746_PI14_FUNC_EVENTOUT 0x8e10
+#define STM32F746_PI14_FUNC_ANALOG 0x8e11
+
+#define STM32F746_PI15_FUNC_GPIO 0x8f00
+#define STM32F746_PI15_FUNC_LCD_R0 0x8f0f
+#define STM32F746_PI15_FUNC_EVENTOUT 0x8f10
+#define STM32F746_PI15_FUNC_ANALOG 0x8f11
+
+
+#define STM32F746_PJ0_FUNC_GPIO 0x9000
+#define STM32F746_PJ0_FUNC_LCD_R1 0x900f
+#define STM32F746_PJ0_FUNC_EVENTOUT 0x9010
+#define STM32F746_PJ0_FUNC_ANALOG 0x9011
+
+#define STM32F746_PJ1_FUNC_GPIO 0x9100
+#define STM32F746_PJ1_FUNC_LCD_R2 0x910f
+#define STM32F746_PJ1_FUNC_EVENTOUT 0x9110
+#define STM32F746_PJ1_FUNC_ANALOG 0x9111
+
+#define STM32F746_PJ2_FUNC_GPIO 0x9200
+#define STM32F746_PJ2_FUNC_LCD_R3 0x920f
+#define STM32F746_PJ2_FUNC_EVENTOUT 0x9210
+#define STM32F746_PJ2_FUNC_ANALOG 0x9211
+
+#define STM32F746_PJ3_FUNC_GPIO 0x9300
+#define STM32F746_PJ3_FUNC_LCD_R4 0x930f
+#define STM32F746_PJ3_FUNC_EVENTOUT 0x9310
+#define STM32F746_PJ3_FUNC_ANALOG 0x9311
+
+#define STM32F746_PJ4_FUNC_GPIO 0x9400
+#define STM32F746_PJ4_FUNC_LCD_R5 0x940f
+#define STM32F746_PJ4_FUNC_EVENTOUT 0x9410
+#define STM32F746_PJ4_FUNC_ANALOG 0x9411
+
+#define STM32F746_PJ5_FUNC_GPIO 0x9500
+#define STM32F746_PJ5_FUNC_LCD_R6 0x950f
+#define STM32F746_PJ5_FUNC_EVENTOUT 0x9510
+#define STM32F746_PJ5_FUNC_ANALOG 0x9511
+
+#define STM32F746_PJ6_FUNC_GPIO 0x9600
+#define STM32F746_PJ6_FUNC_LCD_R7 0x960f
+#define STM32F746_PJ6_FUNC_EVENTOUT 0x9610
+#define STM32F746_PJ6_FUNC_ANALOG 0x9611
+
+#define STM32F746_PJ7_FUNC_GPIO 0x9700
+#define STM32F746_PJ7_FUNC_LCD_G0 0x970f
+#define STM32F746_PJ7_FUNC_EVENTOUT 0x9710
+#define STM32F746_PJ7_FUNC_ANALOG 0x9711
+
+#define STM32F746_PJ8_FUNC_GPIO 0x9800
+#define STM32F746_PJ8_FUNC_LCD_G1 0x980f
+#define STM32F746_PJ8_FUNC_EVENTOUT 0x9810
+#define STM32F746_PJ8_FUNC_ANALOG 0x9811
+
+#define STM32F746_PJ9_FUNC_GPIO 0x9900
+#define STM32F746_PJ9_FUNC_LCD_G2 0x990f
+#define STM32F746_PJ9_FUNC_EVENTOUT 0x9910
+#define STM32F746_PJ9_FUNC_ANALOG 0x9911
+
+#define STM32F746_PJ10_FUNC_GPIO 0x9a00
+#define STM32F746_PJ10_FUNC_LCD_G3 0x9a0f
+#define STM32F746_PJ10_FUNC_EVENTOUT 0x9a10
+#define STM32F746_PJ10_FUNC_ANALOG 0x9a11
+
+#define STM32F746_PJ11_FUNC_GPIO 0x9b00
+#define STM32F746_PJ11_FUNC_LCD_G4 0x9b0f
+#define STM32F746_PJ11_FUNC_EVENTOUT 0x9b10
+#define STM32F746_PJ11_FUNC_ANALOG 0x9b11
+
+#define STM32F746_PJ12_FUNC_GPIO 0x9c00
+#define STM32F746_PJ12_FUNC_LCD_B0 0x9c0f
+#define STM32F746_PJ12_FUNC_EVENTOUT 0x9c10
+#define STM32F746_PJ12_FUNC_ANALOG 0x9c11
+
+#define STM32F746_PJ13_FUNC_GPIO 0x9d00
+#define STM32F746_PJ13_FUNC_LCD_B1 0x9d0f
+#define STM32F746_PJ13_FUNC_EVENTOUT 0x9d10
+#define STM32F746_PJ13_FUNC_ANALOG 0x9d11
+
+#define STM32F746_PJ14_FUNC_GPIO 0x9e00
+#define STM32F746_PJ14_FUNC_LCD_B2 0x9e0f
+#define STM32F746_PJ14_FUNC_EVENTOUT 0x9e10
+#define STM32F746_PJ14_FUNC_ANALOG 0x9e11
+
+#define STM32F746_PJ15_FUNC_GPIO 0x9f00
+#define STM32F746_PJ15_FUNC_LCD_B3 0x9f0f
+#define STM32F746_PJ15_FUNC_EVENTOUT 0x9f10
+#define STM32F746_PJ15_FUNC_ANALOG 0x9f11
+
+
+#define STM32F746_PK0_FUNC_GPIO 0xa000
+#define STM32F746_PK0_FUNC_LCD_G5 0xa00f
+#define STM32F746_PK0_FUNC_EVENTOUT 0xa010
+#define STM32F746_PK0_FUNC_ANALOG 0xa011
+
+#define STM32F746_PK1_FUNC_GPIO 0xa100
+#define STM32F746_PK1_FUNC_LCD_G6 0xa10f
+#define STM32F746_PK1_FUNC_EVENTOUT 0xa110
+#define STM32F746_PK1_FUNC_ANALOG 0xa111
+
+#define STM32F746_PK2_FUNC_GPIO 0xa200
+#define STM32F746_PK2_FUNC_LCD_G7 0xa20f
+#define STM32F746_PK2_FUNC_EVENTOUT 0xa210
+#define STM32F746_PK2_FUNC_ANALOG 0xa211
+
+#define STM32F746_PK3_FUNC_GPIO 0xa300
+#define STM32F746_PK3_FUNC_LCD_B4 0xa30f
+#define STM32F746_PK3_FUNC_EVENTOUT 0xa310
+#define STM32F746_PK3_FUNC_ANALOG 0xa311
+
+#define STM32F746_PK4_FUNC_GPIO 0xa400
+#define STM32F746_PK4_FUNC_LCD_B5 0xa40f
+#define STM32F746_PK4_FUNC_EVENTOUT 0xa410
+#define STM32F746_PK4_FUNC_ANALOG 0xa411
+
+#define STM32F746_PK5_FUNC_GPIO 0xa500
+#define STM32F746_PK5_FUNC_LCD_B6 0xa50f
+#define STM32F746_PK5_FUNC_EVENTOUT 0xa510
+#define STM32F746_PK5_FUNC_ANALOG 0xa511
+
+#define STM32F746_PK6_FUNC_GPIO 0xa600
+#define STM32F746_PK6_FUNC_LCD_B7 0xa60f
+#define STM32F746_PK6_FUNC_EVENTOUT 0xa610
+#define STM32F746_PK6_FUNC_ANALOG 0xa611
+
+#define STM32F746_PK7_FUNC_GPIO 0xa700
+#define STM32F746_PK7_FUNC_LCD_DE 0xa70f
+#define STM32F746_PK7_FUNC_EVENTOUT 0xa710
+#define STM32F746_PK7_FUNC_ANALOG 0xa711
+
+#endif /* _DT_BINDINGS_STM32F746_PINFUNC_H */
index c82794f..491a917 100644 (file)
@@ -197,7 +197,7 @@ static inline int wb_congested(struct bdi_writeback *wb, int cong_bits)
 }
 
 long congestion_wait(int sync, long timeout);
-long wait_iff_congested(struct zone *zone, int sync, long timeout);
+long wait_iff_congested(struct pglist_data *pgdat, int sync, long timeout);
 int pdflush_proc_obsolete(struct ctl_table *table, int write,
                void __user *buffer, size_t *lenp, loff_t *ppos);
 
index c96db9c..adf3307 100644 (file)
@@ -1665,7 +1665,7 @@ static inline bool integrity_req_gap_front_merge(struct request *req,
  */
 struct blk_dax_ctl {
        sector_t sector;
-       void __pmem *addr;
+       void *addr;
        long size;
        pfn_t pfn;
 };
@@ -1676,8 +1676,8 @@ struct block_device_operations {
        int (*rw_page)(struct block_device *, sector_t, struct page *, int rw);
        int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
        int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
-       long (*direct_access)(struct block_device *, sector_t, void __pmem **,
-                       pfn_t *, long);
+       long (*direct_access)(struct block_device *, sector_t, void **, pfn_t *,
+                       long);
        unsigned int (*check_events) (struct gendisk *disk,
                                      unsigned int clearing);
        /* ->media_changed() is DEPRECATED, use ->check_events() instead */
index 1a02dab..d4e106b 100644 (file)
@@ -1,6 +1,18 @@
 #ifndef _LINUX_COMPACTION_H
 #define _LINUX_COMPACTION_H
 
+/*
+ * Determines how hard direct compaction should try to succeed.
+ * Lower value means higher priority, analogically to reclaim priority.
+ */
+enum compact_priority {
+       COMPACT_PRIO_SYNC_LIGHT,
+       MIN_COMPACT_PRIORITY = COMPACT_PRIO_SYNC_LIGHT,
+       DEF_COMPACT_PRIORITY = COMPACT_PRIO_SYNC_LIGHT,
+       COMPACT_PRIO_ASYNC,
+       INIT_COMPACT_PRIORITY = COMPACT_PRIO_ASYNC
+};
+
 /* Return values for compact_zone() and try_to_compact_pages() */
 /* When adding new states, please adjust include/trace/events/compaction.h */
 enum compact_result {
@@ -43,14 +55,6 @@ enum compact_result {
        COMPACT_PARTIAL,
 };
 
-/* Used to signal whether compaction detected need_sched() or lock contention */
-/* No contention detected */
-#define COMPACT_CONTENDED_NONE 0
-/* Either need_sched() was true or fatal signal pending */
-#define COMPACT_CONTENDED_SCHED        1
-/* Zone lock or lru_lock was contended in async compaction */
-#define COMPACT_CONTENDED_LOCK 2
-
 struct alloc_context; /* in mm/internal.h */
 
 #ifdef CONFIG_COMPACTION
@@ -64,9 +68,8 @@ extern int sysctl_compact_unevictable_allowed;
 
 extern int fragmentation_index(struct zone *zone, unsigned int order);
 extern enum compact_result try_to_compact_pages(gfp_t gfp_mask,
-                       unsigned int order,
-               unsigned int alloc_flags, const struct alloc_context *ac,
-               enum migrate_mode mode, int *contended);
+               unsigned int order, unsigned int alloc_flags,
+               const struct alloc_context *ac, enum compact_priority prio);
 extern void compact_pgdat(pg_data_t *pgdat, int order);
 extern void reset_isolation_suitable(pg_data_t *pgdat);
 extern enum compact_result compaction_suitable(struct zone *zone, int order,
@@ -151,14 +154,6 @@ extern void kcompactd_stop(int nid);
 extern void wakeup_kcompactd(pg_data_t *pgdat, int order, int classzone_idx);
 
 #else
-static inline enum compact_result try_to_compact_pages(gfp_t gfp_mask,
-                       unsigned int order, int alloc_flags,
-                       const struct alloc_context *ac,
-                       enum migrate_mode mode, int *contended)
-{
-       return COMPACT_CONTINUE;
-}
-
 static inline void compact_pgdat(pg_data_t *pgdat, int order)
 {
 }
index 2e853b6..1bb9548 100644 (file)
@@ -17,7 +17,6 @@
 # define __release(x)  __context__(x,-1)
 # define __cond_lock(x,c)      ((c) ? ({ __acquire(x); 1; }) : 0)
 # define __percpu      __attribute__((noderef, address_space(3)))
-# define __pmem                __attribute__((noderef, address_space(5)))
 #ifdef CONFIG_SPARSE_RCU_POINTER
 # define __rcu         __attribute__((noderef, address_space(4)))
 #else /* CONFIG_SPARSE_RCU_POINTER */
@@ -45,7 +44,6 @@ extern void __chk_io_ptr(const volatile void __iomem *);
 # define __cond_lock(x,c) (c)
 # define __percpu
 # define __rcu
-# define __pmem
 # define __private
 # define ACCESS_PRIVATE(p, member) ((p)->member)
 #endif /* __CHECKER__ */
index f53fa05..98044a8 100644 (file)
@@ -133,14 +133,15 @@ struct dentry_operations {
        int (*d_compare)(const struct dentry *, const struct dentry *,
                        unsigned int, const char *, const struct qstr *);
        int (*d_delete)(const struct dentry *);
+       int (*d_init)(struct dentry *);
        void (*d_release)(struct dentry *);
        void (*d_prune)(struct dentry *);
        void (*d_iput)(struct dentry *, struct inode *);
        char *(*d_dname)(struct dentry *, char *, int);
        struct vfsmount *(*d_automount)(struct path *);
        int (*d_manage)(struct dentry *, bool);
-       struct inode *(*d_select_inode)(struct dentry *, unsigned);
-       struct dentry *(*d_real)(struct dentry *, struct inode *);
+       struct dentry *(*d_real)(struct dentry *, const struct inode *,
+                                unsigned int);
 } ____cacheline_aligned;
 
 /*
@@ -206,10 +207,8 @@ struct dentry_operations {
 
 #define DCACHE_MAY_FREE                        0x00800000
 #define DCACHE_FALLTHRU                        0x01000000 /* Fall through to lower layer */
-#define DCACHE_OP_SELECT_INODE         0x02000000 /* Unioned entry: dcache op selects inode */
-
-#define DCACHE_ENCRYPTED_WITH_KEY      0x04000000 /* dir is encrypted with a valid key */
-#define DCACHE_OP_REAL                 0x08000000
+#define DCACHE_ENCRYPTED_WITH_KEY      0x02000000 /* dir is encrypted with a valid key */
+#define DCACHE_OP_REAL                 0x04000000
 
 #define DCACHE_PAR_LOOKUP              0x10000000 /* being looked up (with parent locked shared) */
 #define DCACHE_DENTRY_CURSOR           0x20000000
@@ -557,25 +556,27 @@ static inline struct dentry *d_backing_dentry(struct dentry *upper)
        return upper;
 }
 
-static inline struct dentry *d_real(struct dentry *dentry)
+/**
+ * d_real - Return the real dentry
+ * @dentry: the dentry to query
+ * @inode: inode to select the dentry from multiple layers (can be NULL)
+ * @flags: open flags to control copy-up behavior
+ *
+ * If dentry is on an union/overlay, then return the underlying, real dentry.
+ * Otherwise return the dentry itself.
+ *
+ * See also: Documentation/filesystems/vfs.txt
+ */
+static inline struct dentry *d_real(struct dentry *dentry,
+                                   const struct inode *inode,
+                                   unsigned int flags)
 {
        if (unlikely(dentry->d_flags & DCACHE_OP_REAL))
-               return dentry->d_op->d_real(dentry, NULL);
+               return dentry->d_op->d_real(dentry, inode, flags);
        else
                return dentry;
 }
 
-static inline struct inode *vfs_select_inode(struct dentry *dentry,
-                                            unsigned open_flags)
-{
-       struct inode *inode = d_inode(dentry);
-
-       if (inode && unlikely(dentry->d_flags & DCACHE_OP_SELECT_INODE))
-               inode = dentry->d_op->d_select_inode(dentry, open_flags);
-
-       return inode;
-}
-
 /**
  * d_real_inode - Return the real inode
  * @dentry: The dentry to query
@@ -585,7 +586,7 @@ static inline struct inode *vfs_select_inode(struct dentry *dentry,
  */
 static inline struct inode *d_real_inode(struct dentry *dentry)
 {
-       return d_backing_inode(d_real(dentry));
+       return d_backing_inode(d_real(dentry, NULL, 0));
 }
 
 
index b0db857..91acfce 100644 (file)
@@ -131,7 +131,7 @@ typedef int (*dm_busy_fn) (struct dm_target *ti);
  * >= 0 : the number of bytes accessible at the address
  */
 typedef long (*dm_direct_access_fn) (struct dm_target *ti, sector_t sector,
-                                    void __pmem **kaddr, pfn_t *pfn, long size);
+                                    void **kaddr, pfn_t *pfn, long size);
 
 void dm_error(const char *message);
 
index f2a69f2..50ccf84 100644 (file)
@@ -457,7 +457,6 @@ struct block_device {
        struct inode *          bd_inode;       /* will die */
        struct super_block *    bd_super;
        struct mutex            bd_mutex;       /* open/close mutex */
-       struct list_head        bd_inodes;
        void *                  bd_claiming;
        void *                  bd_holder;
        int                     bd_holders;
@@ -1271,12 +1270,7 @@ static inline struct inode *file_inode(const struct file *f)
 
 static inline struct dentry *file_dentry(const struct file *file)
 {
-       struct dentry *dentry = file->f_path.dentry;
-
-       if (unlikely(dentry->d_flags & DCACHE_OP_REAL))
-               return dentry->d_op->d_real(dentry, file_inode(file));
-       else
-               return dentry;
+       return d_real(file->f_path.dentry, file_inode(file), 0);
 }
 
 static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl)
index 0141f25..eed9e85 100644 (file)
@@ -51,18 +51,6 @@ static inline int fsnotify_perm(struct file *file, int mask)
        return fsnotify(inode, fsnotify_mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
 }
 
-/*
- * fsnotify_d_move - dentry has been moved
- */
-static inline void fsnotify_d_move(struct dentry *dentry)
-{
-       /*
-        * On move we need to update dentry->d_flags to indicate if the new parent
-        * cares about events from this dentry.
-        */
-       __fsnotify_update_dcache_flags(dentry);
-}
-
 /*
  * fsnotify_link_count - inode's link count changed
  */
index 29f9175..58205f3 100644 (file)
@@ -267,10 +267,8 @@ static inline int fsnotify_inode_watches_children(struct inode *inode)
  * Update the dentry with a flag indicating the interest of its parent to receive
  * filesystem events when those events happens to this dentry->d_inode.
  */
-static inline void __fsnotify_update_dcache_flags(struct dentry *dentry)
+static inline void fsnotify_update_flags(struct dentry *dentry)
 {
-       struct dentry *parent;
-
        assert_spin_locked(&dentry->d_lock);
 
        /*
@@ -280,21 +278,12 @@ static inline void __fsnotify_update_dcache_flags(struct dentry *dentry)
         * find our entry, so it will spin until we complete here, and update
         * us with the new state.
         */
-       parent = dentry->d_parent;
-       if (parent->d_inode && fsnotify_inode_watches_children(parent->d_inode))
+       if (fsnotify_inode_watches_children(dentry->d_parent->d_inode))
                dentry->d_flags |= DCACHE_FSNOTIFY_PARENT_WATCHED;
        else
                dentry->d_flags &= ~DCACHE_FSNOTIFY_PARENT_WATCHED;
 }
 
-/*
- * fsnotify_d_instantiate - instantiate a dentry for inode
- */
-static inline void __fsnotify_d_instantiate(struct dentry *dentry)
-{
-       __fsnotify_update_dcache_flags(dentry);
-}
-
 /* called from fsnotify listeners, such as fanotify or dnotify */
 
 /* create a new group */
@@ -386,10 +375,7 @@ static inline void __fsnotify_inode_delete(struct inode *inode)
 static inline void __fsnotify_vfsmount_delete(struct vfsmount *mnt)
 {}
 
-static inline void __fsnotify_update_dcache_flags(struct dentry *dentry)
-{}
-
-static inline void __fsnotify_d_instantiate(struct dentry *dentry)
+static inline void fsnotify_update_flags(struct dentry *dentry)
 {}
 
 static inline u32 fsnotify_get_cookie(void)
index c29e9d3..f8041f9 100644 (file)
@@ -237,9 +237,11 @@ struct vm_area_struct;
  *   are expected to be movable via page reclaim or page migration. Typically,
  *   pages on the LRU would also be allocated with GFP_HIGHUSER_MOVABLE.
  *
- * GFP_TRANSHUGE is used for THP allocations. They are compound allocations
- *   that will fail quickly if memory is not available and will not wake
- *   kswapd on failure.
+ * GFP_TRANSHUGE and GFP_TRANSHUGE_LIGHT are used for THP allocations. They are
+ *   compound allocations that will generally fail quickly if memory is not
+ *   available and will not wake kswapd/kcompactd on failure. The _LIGHT
+ *   version does not attempt reclaim/compaction at all and is by default used
+ *   in page fault path, while the non-light is used by khugepaged.
  */
 #define GFP_ATOMIC     (__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM)
 #define GFP_KERNEL     (__GFP_RECLAIM | __GFP_IO | __GFP_FS)
@@ -254,9 +256,9 @@ struct vm_area_struct;
 #define GFP_DMA32      __GFP_DMA32
 #define GFP_HIGHUSER   (GFP_USER | __GFP_HIGHMEM)
 #define GFP_HIGHUSER_MOVABLE   (GFP_HIGHUSER | __GFP_MOVABLE)
-#define GFP_TRANSHUGE  ((GFP_HIGHUSER_MOVABLE | __GFP_COMP | \
-                        __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN) & \
-                        ~__GFP_RECLAIM)
+#define GFP_TRANSHUGE_LIGHT    ((GFP_HIGHUSER_MOVABLE | __GFP_COMP | \
+                        __GFP_NOMEMALLOC | __GFP_NOWARN) & ~__GFP_RECLAIM)
+#define GFP_TRANSHUGE  (GFP_TRANSHUGE_LIGHT | __GFP_DIRECT_RECLAIM)
 
 /* Convert GFP flags to their corresponding migrate type */
 #define GFP_MOVABLE_MASK (__GFP_RECLAIMABLE|__GFP_MOVABLE)
index 92ce91c..6f14de4 100644 (file)
@@ -11,7 +11,7 @@ extern struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
                                          unsigned long addr,
                                          pmd_t *pmd,
                                          unsigned int flags);
-extern int madvise_free_huge_pmd(struct mmu_gather *tlb,
+extern bool madvise_free_huge_pmd(struct mmu_gather *tlb,
                        struct vm_area_struct *vma,
                        pmd_t *pmd, unsigned long addr, unsigned long next);
 extern int zap_huge_pmd(struct mmu_gather *tlb,
index ac4b3c4..c9cf374 100644 (file)
@@ -77,6 +77,7 @@ void kasan_free_shadow(const struct vm_struct *vm);
 
 size_t ksize(const void *);
 static inline void kasan_unpoison_slab(const void *ptr) { ksize(ptr); }
+size_t kasan_metadata_size(struct kmem_cache *cache);
 
 #else /* CONFIG_KASAN */
 
@@ -121,6 +122,7 @@ static inline int kasan_module_alloc(void *addr, size_t size) { return 0; }
 static inline void kasan_free_shadow(const struct vm_struct *vm) {}
 
 static inline void kasan_unpoison_slab(const void *ptr) { }
+static inline size_t kasan_metadata_size(struct kmem_cache *cache) { return 0; }
 
 #endif /* CONFIG_KASAN */
 
index a19bcf9..410deca 100644 (file)
@@ -177,7 +177,7 @@ extern int kdb_get_kbd_char(void);
 static inline
 int kdb_process_cpu(const struct task_struct *p)
 {
-       unsigned int cpu = task_thread_info(p)->cpu;
+       unsigned int cpu = task_cpu(p);
        if (cpu > num_possible_cpus())
                cpu = 0;
        return cpu;
index 0c3c30c..b519e13 100644 (file)
@@ -52,6 +52,7 @@ typedef int (*ndctl_fn)(struct nvdimm_bus_descriptor *nd_desc,
 
 struct nd_namespace_label;
 struct nvdimm_drvdata;
+
 struct nd_mapping {
        struct nvdimm *nvdimm;
        struct nd_namespace_label **labels;
@@ -69,6 +70,7 @@ struct nd_mapping {
 struct nvdimm_bus_descriptor {
        const struct attribute_group **attr_groups;
        unsigned long cmd_mask;
+       struct module *module;
        char *provider_name;
        ndctl_fn ndctl;
        int (*flush_probe)(struct nvdimm_bus_descriptor *nd_desc);
@@ -99,13 +101,21 @@ struct nd_region_desc {
        unsigned long flags;
 };
 
+struct device;
+void *devm_nvdimm_memremap(struct device *dev, resource_size_t offset,
+               size_t size, unsigned long flags);
+static inline void __iomem *devm_nvdimm_ioremap(struct device *dev,
+               resource_size_t offset, size_t size)
+{
+       return (void __iomem *) devm_nvdimm_memremap(dev, offset, size, 0);
+}
+
 struct nvdimm_bus;
 struct module;
 struct device;
 struct nd_blk_region;
 struct nd_blk_region_desc {
        int (*enable)(struct nvdimm_bus *nvdimm_bus, struct device *dev);
-       void (*disable)(struct nvdimm_bus *nvdimm_bus, struct device *dev);
        int (*do_io)(struct nd_blk_region *ndbr, resource_size_t dpa,
                        void *iobuf, u64 len, int rw);
        struct nd_region_desc ndr_desc;
@@ -119,22 +129,22 @@ static inline struct nd_blk_region_desc *to_blk_region_desc(
 }
 
 int nvdimm_bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length);
-struct nvdimm_bus *__nvdimm_bus_register(struct device *parent,
-               struct nvdimm_bus_descriptor *nfit_desc, struct module *module);
-#define nvdimm_bus_register(parent, desc) \
-       __nvdimm_bus_register(parent, desc, THIS_MODULE)
+struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
+               struct nvdimm_bus_descriptor *nfit_desc);
 void nvdimm_bus_unregister(struct nvdimm_bus *nvdimm_bus);
 struct nvdimm_bus *to_nvdimm_bus(struct device *dev);
 struct nvdimm *to_nvdimm(struct device *dev);
 struct nd_region *to_nd_region(struct device *dev);
 struct nd_blk_region *to_nd_blk_region(struct device *dev);
 struct nvdimm_bus_descriptor *to_nd_desc(struct nvdimm_bus *nvdimm_bus);
+struct device *to_nvdimm_bus_dev(struct nvdimm_bus *nvdimm_bus);
 const char *nvdimm_name(struct nvdimm *nvdimm);
 unsigned long nvdimm_cmd_mask(struct nvdimm *nvdimm);
 void *nvdimm_provider_data(struct nvdimm *nvdimm);
 struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data,
                const struct attribute_group **groups, unsigned long flags,
-               unsigned long cmd_mask);
+               unsigned long cmd_mask, int num_flush,
+               struct resource *flush_wpq);
 const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd);
 const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd);
 u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd,
@@ -156,4 +166,6 @@ struct nvdimm *nd_blk_region_to_dimm(struct nd_blk_region *ndbr);
 unsigned int nd_region_acquire_lane(struct nd_region *nd_region);
 void nd_region_release_lane(struct nd_region *nd_region, unsigned int lane);
 u64 nd_fletcher64(void *addr, size_t len, bool le);
+void nvdimm_flush(struct nd_region *nd_region);
+int nvdimm_has_flush(struct nd_region *nd_region);
 #endif /* __LIBNVDIMM_H__ */
index 6c14b61..2925da2 100644 (file)
@@ -332,6 +332,7 @@ phys_addr_t memblock_mem_size(unsigned long limit_pfn);
 phys_addr_t memblock_start_of_DRAM(void);
 phys_addr_t memblock_end_of_DRAM(void);
 void memblock_enforce_memory_limit(phys_addr_t memory_limit);
+void memblock_mem_limit_remove_map(phys_addr_t limit);
 bool memblock_is_memory(phys_addr_t addr);
 int memblock_is_map_memory(phys_addr_t addr);
 int memblock_is_region_memory(phys_addr_t base, phys_addr_t size);
index 71aff73..5d8ca6e 100644 (file)
@@ -52,7 +52,7 @@ enum mem_cgroup_stat_index {
        MEM_CGROUP_STAT_SWAP,           /* # of pages, swapped out */
        MEM_CGROUP_STAT_NSTATS,
        /* default hierarchy stats */
-       MEMCG_KERNEL_STACK = MEM_CGROUP_STAT_NSTATS,
+       MEMCG_KERNEL_STACK_KB = MEM_CGROUP_STAT_NSTATS,
        MEMCG_SLAB_RECLAIMABLE,
        MEMCG_SLAB_UNRECLAIMABLE,
        MEMCG_SOCK,
@@ -60,7 +60,7 @@ enum mem_cgroup_stat_index {
 };
 
 struct mem_cgroup_reclaim_cookie {
-       struct zone *zone;
+       pg_data_t *pgdat;
        int priority;
        unsigned int generation;
 };
@@ -118,7 +118,7 @@ struct mem_cgroup_reclaim_iter {
 /*
  * per-zone information in memory controller.
  */
-struct mem_cgroup_per_zone {
+struct mem_cgroup_per_node {
        struct lruvec           lruvec;
        unsigned long           lru_size[NR_LRU_LISTS];
 
@@ -132,10 +132,6 @@ struct mem_cgroup_per_zone {
                                                /* use container_of        */
 };
 
-struct mem_cgroup_per_node {
-       struct mem_cgroup_per_zone zoneinfo[MAX_NR_ZONES];
-};
-
 struct mem_cgroup_threshold {
        struct eventfd_ctx *eventfd;
        unsigned long threshold;
@@ -314,8 +310,46 @@ void mem_cgroup_uncharge_list(struct list_head *page_list);
 
 void mem_cgroup_migrate(struct page *oldpage, struct page *newpage);
 
-struct lruvec *mem_cgroup_zone_lruvec(struct zone *, struct mem_cgroup *);
-struct lruvec *mem_cgroup_page_lruvec(struct page *, struct zone *);
+static struct mem_cgroup_per_node *
+mem_cgroup_nodeinfo(struct mem_cgroup *memcg, int nid)
+{
+       return memcg->nodeinfo[nid];
+}
+
+/**
+ * mem_cgroup_lruvec - get the lru list vector for a node or a memcg zone
+ * @node: node of the wanted lruvec
+ * @memcg: memcg of the wanted lruvec
+ *
+ * Returns the lru list vector holding pages for a given @node or a given
+ * @memcg and @zone. This can be the node lruvec, if the memory controller
+ * is disabled.
+ */
+static inline struct lruvec *mem_cgroup_lruvec(struct pglist_data *pgdat,
+                               struct mem_cgroup *memcg)
+{
+       struct mem_cgroup_per_node *mz;
+       struct lruvec *lruvec;
+
+       if (mem_cgroup_disabled()) {
+               lruvec = node_lruvec(pgdat);
+               goto out;
+       }
+
+       mz = mem_cgroup_nodeinfo(memcg, pgdat->node_id);
+       lruvec = &mz->lruvec;
+out:
+       /*
+        * Since a node can be onlined after the mem_cgroup was created,
+        * we have to be prepared to initialize lruvec->pgdat here;
+        * and if offlined then reonlined, we need to reinitialize it.
+        */
+       if (unlikely(lruvec->pgdat != pgdat))
+               lruvec->pgdat = pgdat;
+       return lruvec;
+}
+
+struct lruvec *mem_cgroup_page_lruvec(struct page *, struct pglist_data *);
 
 bool task_in_mem_cgroup(struct task_struct *task, struct mem_cgroup *memcg);
 struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p);
@@ -404,9 +438,9 @@ unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
 static inline
 unsigned long mem_cgroup_get_lru_size(struct lruvec *lruvec, enum lru_list lru)
 {
-       struct mem_cgroup_per_zone *mz;
+       struct mem_cgroup_per_node *mz;
 
-       mz = container_of(lruvec, struct mem_cgroup_per_zone, lruvec);
+       mz = container_of(lruvec, struct mem_cgroup_per_node, lruvec);
        return mz->lru_size[lru];
 }
 
@@ -477,7 +511,7 @@ static inline void mem_cgroup_dec_page_stat(struct page *page,
        mem_cgroup_update_page_stat(page, idx, -1);
 }
 
-unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
+unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,
                                                gfp_t gfp_mask,
                                                unsigned long *total_scanned);
 
@@ -568,16 +602,16 @@ static inline void mem_cgroup_migrate(struct page *old, struct page *new)
 {
 }
 
-static inline struct lruvec *mem_cgroup_zone_lruvec(struct zone *zone,
-                                                   struct mem_cgroup *memcg)
+static inline struct lruvec *mem_cgroup_lruvec(struct pglist_data *pgdat,
+                               struct mem_cgroup *memcg)
 {
-       return &zone->lruvec;
+       return node_lruvec(pgdat);
 }
 
 static inline struct lruvec *mem_cgroup_page_lruvec(struct page *page,
-                                                   struct zone *zone)
+                                                   struct pglist_data *pgdat)
 {
-       return &zone->lruvec;
+       return &pgdat->lruvec;
 }
 
 static inline bool mm_match_cgroup(struct mm_struct *mm,
@@ -681,7 +715,7 @@ static inline void mem_cgroup_dec_page_stat(struct page *page,
 }
 
 static inline
-unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
+unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,
                                            gfp_t gfp_mask,
                                            unsigned long *total_scanned)
 {
index bcaa634..9341619 100644 (file)
@@ -26,7 +26,7 @@ struct vmem_altmap {
 unsigned long vmem_altmap_offset(struct vmem_altmap *altmap);
 void vmem_altmap_free(struct vmem_altmap *altmap, unsigned long nr_pfns);
 
-#if defined(CONFIG_SPARSEMEM_VMEMMAP) && defined(CONFIG_ZONE_DEVICE)
+#ifdef CONFIG_ZONE_DEVICE
 struct vmem_altmap *to_vmem_altmap(unsigned long memmap_start);
 #else
 static inline struct vmem_altmap *to_vmem_altmap(unsigned long memmap_start)
index 192c1bb..08ed53e 100644 (file)
@@ -933,6 +933,11 @@ static inline struct zone *page_zone(const struct page *page)
        return &NODE_DATA(page_to_nid(page))->node_zones[page_zonenum(page)];
 }
 
+static inline pg_data_t *page_pgdat(const struct page *page)
+{
+       return NODE_DATA(page_to_nid(page));
+}
+
 #ifdef SECTION_IN_PAGE_FLAGS
 static inline void set_page_section(struct page *page, unsigned long section)
 {
@@ -973,11 +978,21 @@ static inline struct mem_cgroup *page_memcg(struct page *page)
 {
        return page->mem_cgroup;
 }
+static inline struct mem_cgroup *page_memcg_rcu(struct page *page)
+{
+       WARN_ON_ONCE(!rcu_read_lock_held());
+       return READ_ONCE(page->mem_cgroup);
+}
 #else
 static inline struct mem_cgroup *page_memcg(struct page *page)
 {
        return NULL;
 }
+static inline struct mem_cgroup *page_memcg_rcu(struct page *page)
+{
+       WARN_ON_ONCE(!rcu_read_lock_held());
+       return NULL;
+}
 #endif
 
 /*
@@ -2284,6 +2299,8 @@ static inline int in_gate_area(struct mm_struct *mm, unsigned long addr)
 }
 #endif /* __HAVE_ARCH_GATE_AREA */
 
+extern bool process_shares_mm(struct task_struct *p, struct mm_struct *mm);
+
 #ifdef CONFIG_SYSCTL
 extern int sysctl_drop_caches;
 int drop_caches_sysctl_handler(struct ctl_table *, int,
index 5bd29ba..71613e8 100644 (file)
@@ -23,25 +23,30 @@ static inline int page_is_file_cache(struct page *page)
 }
 
 static __always_inline void __update_lru_size(struct lruvec *lruvec,
-                               enum lru_list lru, int nr_pages)
+                               enum lru_list lru, enum zone_type zid,
+                               int nr_pages)
 {
-       __mod_zone_page_state(lruvec_zone(lruvec), NR_LRU_BASE + lru, nr_pages);
+       struct pglist_data *pgdat = lruvec_pgdat(lruvec);
+
+       __mod_node_page_state(pgdat, NR_LRU_BASE + lru, nr_pages);
+       __mod_zone_page_state(&pgdat->node_zones[zid],
+                               NR_ZONE_LRU_BASE + lru, nr_pages);
 }
 
 static __always_inline void update_lru_size(struct lruvec *lruvec,
-                               enum lru_list lru, int nr_pages)
+                               enum lru_list lru, enum zone_type zid,
+                               int nr_pages)
 {
+       __update_lru_size(lruvec, lru, zid, nr_pages);
 #ifdef CONFIG_MEMCG
        mem_cgroup_update_lru_size(lruvec, lru, nr_pages);
-#else
-       __update_lru_size(lruvec, lru, nr_pages);
 #endif
 }
 
 static __always_inline void add_page_to_lru_list(struct page *page,
                                struct lruvec *lruvec, enum lru_list lru)
 {
-       update_lru_size(lruvec, lru, hpage_nr_pages(page));
+       update_lru_size(lruvec, lru, page_zonenum(page), hpage_nr_pages(page));
        list_add(&page->lru, &lruvec->lists[lru]);
 }
 
@@ -49,7 +54,7 @@ static __always_inline void del_page_from_lru_list(struct page *page,
                                struct lruvec *lruvec, enum lru_list lru)
 {
        list_del(&page->lru);
-       update_lru_size(lruvec, lru, -hpage_nr_pages(page));
+       update_lru_size(lruvec, lru, page_zonenum(page), -hpage_nr_pages(page));
 }
 
 /**
index 79472b2..903200f 100644 (file)
@@ -118,7 +118,7 @@ struct page {
         */
        union {
                struct list_head lru;   /* Pageout list, eg. active_list
-                                        * protected by zone->lru_lock !
+                                        * protected by zone_lru_lock !
                                         * Can be used as a generic list
                                         * by the page owner.
                                         */
index 19425e9..f2e4e90 100644 (file)
@@ -93,7 +93,7 @@ struct free_area {
 struct pglist_data;
 
 /*
- * zone->lock and zone->lru_lock are two of the hottest locks in the kernel.
+ * zone->lock and the zone lru_lock are two of the hottest locks in the kernel.
  * So add a wild amount of padding here to ensure that they fall into separate
  * cachelines.  There are very few zone structures in the machine, so space
  * consumption is not a concern here.
@@ -110,36 +110,20 @@ struct zone_padding {
 enum zone_stat_item {
        /* First 128 byte cacheline (assuming 64 bit words) */
        NR_FREE_PAGES,
-       NR_ALLOC_BATCH,
-       NR_LRU_BASE,
-       NR_INACTIVE_ANON = NR_LRU_BASE, /* must match order of LRU_[IN]ACTIVE */
-       NR_ACTIVE_ANON,         /*  "     "     "   "       "         */
-       NR_INACTIVE_FILE,       /*  "     "     "   "       "         */
-       NR_ACTIVE_FILE,         /*  "     "     "   "       "         */
-       NR_UNEVICTABLE,         /*  "     "     "   "       "         */
+       NR_ZONE_LRU_BASE, /* Used only for compaction and reclaim retry */
+       NR_ZONE_INACTIVE_ANON = NR_ZONE_LRU_BASE,
+       NR_ZONE_ACTIVE_ANON,
+       NR_ZONE_INACTIVE_FILE,
+       NR_ZONE_ACTIVE_FILE,
+       NR_ZONE_UNEVICTABLE,
+       NR_ZONE_WRITE_PENDING,  /* Count of dirty, writeback and unstable pages */
        NR_MLOCK,               /* mlock()ed pages found and moved off LRU */
-       NR_ANON_PAGES,  /* Mapped anonymous pages */
-       NR_FILE_MAPPED, /* pagecache pages mapped into pagetables.
-                          only modified from process context */
-       NR_FILE_PAGES,
-       NR_FILE_DIRTY,
-       NR_WRITEBACK,
        NR_SLAB_RECLAIMABLE,
        NR_SLAB_UNRECLAIMABLE,
        NR_PAGETABLE,           /* used for pagetables */
-       NR_KERNEL_STACK,
+       NR_KERNEL_STACK_KB,     /* measured in KiB */
        /* Second 128 byte cacheline */
-       NR_UNSTABLE_NFS,        /* NFS unstable pages */
        NR_BOUNCE,
-       NR_VMSCAN_WRITE,
-       NR_VMSCAN_IMMEDIATE,    /* Prioritise for reclaim when writeback ends */
-       NR_WRITEBACK_TEMP,      /* Writeback using temporary buffers */
-       NR_ISOLATED_ANON,       /* Temporary isolated pages from anon lru */
-       NR_ISOLATED_FILE,       /* Temporary isolated pages from file lru */
-       NR_SHMEM,               /* shmem pages (included tmpfs/GEM pages) */
-       NR_DIRTIED,             /* page dirtyings since bootup */
-       NR_WRITTEN,             /* page writings since bootup */
-       NR_PAGES_SCANNED,       /* pages scanned since last reclaim */
 #if IS_ENABLED(CONFIG_ZSMALLOC)
        NR_ZSPAGES,             /* allocated in zsmalloc */
 #endif
@@ -151,14 +135,40 @@ enum zone_stat_item {
        NUMA_LOCAL,             /* allocation from local node */
        NUMA_OTHER,             /* allocation from other node */
 #endif
+       NR_FREE_CMA_PAGES,
+       NR_VM_ZONE_STAT_ITEMS };
+
+enum node_stat_item {
+       NR_LRU_BASE,
+       NR_INACTIVE_ANON = NR_LRU_BASE, /* must match order of LRU_[IN]ACTIVE */
+       NR_ACTIVE_ANON,         /*  "     "     "   "       "         */
+       NR_INACTIVE_FILE,       /*  "     "     "   "       "         */
+       NR_ACTIVE_FILE,         /*  "     "     "   "       "         */
+       NR_UNEVICTABLE,         /*  "     "     "   "       "         */
+       NR_ISOLATED_ANON,       /* Temporary isolated pages from anon lru */
+       NR_ISOLATED_FILE,       /* Temporary isolated pages from file lru */
+       NR_PAGES_SCANNED,       /* pages scanned since last reclaim */
        WORKINGSET_REFAULT,
        WORKINGSET_ACTIVATE,
        WORKINGSET_NODERECLAIM,
-       NR_ANON_THPS,
+       NR_ANON_MAPPED, /* Mapped anonymous pages */
+       NR_FILE_MAPPED, /* pagecache pages mapped into pagetables.
+                          only modified from process context */
+       NR_FILE_PAGES,
+       NR_FILE_DIRTY,
+       NR_WRITEBACK,
+       NR_WRITEBACK_TEMP,      /* Writeback using temporary buffers */
+       NR_SHMEM,               /* shmem pages (included tmpfs/GEM pages) */
        NR_SHMEM_THPS,
        NR_SHMEM_PMDMAPPED,
-       NR_FREE_CMA_PAGES,
-       NR_VM_ZONE_STAT_ITEMS };
+       NR_ANON_THPS,
+       NR_UNSTABLE_NFS,        /* NFS unstable pages */
+       NR_VMSCAN_WRITE,
+       NR_VMSCAN_IMMEDIATE,    /* Prioritise for reclaim when writeback ends */
+       NR_DIRTIED,             /* page dirtyings since bootup */
+       NR_WRITTEN,             /* page writings since bootup */
+       NR_VM_NODE_STAT_ITEMS
+};
 
 /*
  * We do arithmetic on the LRU lists in various places in the code,
@@ -215,7 +225,7 @@ struct lruvec {
        /* Evictions & activations on the inactive file list */
        atomic_long_t                   inactive_age;
 #ifdef CONFIG_MEMCG
-       struct zone                     *zone;
+       struct pglist_data *pgdat;
 #endif
 };
 
@@ -267,6 +277,11 @@ struct per_cpu_pageset {
 #endif
 };
 
+struct per_cpu_nodestat {
+       s8 stat_threshold;
+       s8 vm_node_stat_diff[NR_VM_NODE_STAT_ITEMS];
+};
+
 #endif /* !__GENERATING_BOUNDS.H */
 
 enum zone_type {
@@ -348,22 +363,9 @@ struct zone {
 #ifdef CONFIG_NUMA
        int node;
 #endif
-
-       /*
-        * The target ratio of ACTIVE_ANON to INACTIVE_ANON pages on
-        * this zone's LRU.  Maintained by the pageout code.
-        */
-       unsigned int inactive_ratio;
-
        struct pglist_data      *zone_pgdat;
        struct per_cpu_pageset __percpu *pageset;
 
-       /*
-        * This is a per-zone reserve of pages that are not available
-        * to userspace allocations.
-        */
-       unsigned long           totalreserve_pages;
-
 #ifndef CONFIG_SPARSEMEM
        /*
         * Flags for a pageblock_nr_pages block. See pageblock-flags.h.
@@ -372,14 +374,6 @@ struct zone {
        unsigned long           *pageblock_flags;
 #endif /* CONFIG_SPARSEMEM */
 
-#ifdef CONFIG_NUMA
-       /*
-        * zone reclaim becomes active if more unmapped pages exist.
-        */
-       unsigned long           min_unmapped_pages;
-       unsigned long           min_slab_pages;
-#endif /* CONFIG_NUMA */
-
        /* zone_start_pfn == zone_start_paddr >> PAGE_SHIFT */
        unsigned long           zone_start_pfn;
 
@@ -472,24 +466,21 @@ struct zone {
        unsigned long           wait_table_hash_nr_entries;
        unsigned long           wait_table_bits;
 
+       /* Write-intensive fields used from the page allocator */
        ZONE_PADDING(_pad1_)
+
        /* free areas of different sizes */
        struct free_area        free_area[MAX_ORDER];
 
        /* zone flags, see below */
        unsigned long           flags;
 
-       /* Write-intensive fields used from the page allocator */
+       /* Primarily protects free_area */
        spinlock_t              lock;
 
+       /* Write-intensive fields used by compaction and vmstats. */
        ZONE_PADDING(_pad2_)
 
-       /* Write-intensive fields used by page reclaim */
-
-       /* Fields commonly accessed by the page reclaim scanner */
-       spinlock_t              lru_lock;
-       struct lruvec           lruvec;
-
        /*
         * When free pages are below this point, additional steps are taken
         * when reading the number of free pages to avoid per-cpu counter
@@ -527,19 +518,18 @@ struct zone {
        atomic_long_t           vm_stat[NR_VM_ZONE_STAT_ITEMS];
 } ____cacheline_internodealigned_in_smp;
 
-enum zone_flags {
-       ZONE_RECLAIM_LOCKED,            /* prevents concurrent reclaim */
-       ZONE_CONGESTED,                 /* zone has many dirty pages backed by
+enum pgdat_flags {
+       PGDAT_CONGESTED,                /* pgdat has many dirty pages backed by
                                         * a congested BDI
                                         */
-       ZONE_DIRTY,                     /* reclaim scanning has recently found
+       PGDAT_DIRTY,                    /* reclaim scanning has recently found
                                         * many dirty file pages at the tail
                                         * of the LRU.
                                         */
-       ZONE_WRITEBACK,                 /* reclaim scanning has recently found
+       PGDAT_WRITEBACK,                /* reclaim scanning has recently found
                                         * many pages under writeback
                                         */
-       ZONE_FAIR_DEPLETED,             /* fair zone policy batch depleted */
+       PGDAT_RECLAIM_LOCKED,           /* prevents concurrent reclaim */
 };
 
 static inline unsigned long zone_end_pfn(const struct zone *zone)
@@ -663,8 +653,9 @@ typedef struct pglist_data {
        wait_queue_head_t pfmemalloc_wait;
        struct task_struct *kswapd;     /* Protected by
                                           mem_hotplug_begin/end() */
-       int kswapd_max_order;
-       enum zone_type classzone_idx;
+       int kswapd_order;
+       enum zone_type kswapd_classzone_idx;
+
 #ifdef CONFIG_COMPACTION
        int kcompactd_max_order;
        enum zone_type kcompactd_classzone_idx;
@@ -681,6 +672,23 @@ typedef struct pglist_data {
        /* Number of pages migrated during the rate limiting time interval */
        unsigned long numabalancing_migrate_nr_pages;
 #endif
+       /*
+        * This is a per-node reserve of pages that are not available
+        * to userspace allocations.
+        */
+       unsigned long           totalreserve_pages;
+
+#ifdef CONFIG_NUMA
+       /*
+        * zone reclaim becomes active if more unmapped pages exist.
+        */
+       unsigned long           min_unmapped_pages;
+       unsigned long           min_slab_pages;
+#endif /* CONFIG_NUMA */
+
+       /* Write-intensive fields used by page reclaim */
+       ZONE_PADDING(_pad1_)
+       spinlock_t              lru_lock;
 
 #ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT
        /*
@@ -695,6 +703,23 @@ typedef struct pglist_data {
        struct list_head split_queue;
        unsigned long split_queue_len;
 #endif
+
+       /* Fields commonly accessed by the page reclaim scanner */
+       struct lruvec           lruvec;
+
+       /*
+        * The target ratio of ACTIVE_ANON to INACTIVE_ANON pages on
+        * this node's LRU.  Maintained by the pageout code.
+        */
+       unsigned int inactive_ratio;
+
+       unsigned long           flags;
+
+       ZONE_PADDING(_pad2_)
+
+       /* Per-node vmstats */
+       struct per_cpu_nodestat __percpu *per_cpu_nodestats;
+       atomic_long_t           vm_stat[NR_VM_NODE_STAT_ITEMS];
 } pg_data_t;
 
 #define node_present_pages(nid)        (NODE_DATA(nid)->node_present_pages)
@@ -708,6 +733,15 @@ typedef struct pglist_data {
 
 #define node_start_pfn(nid)    (NODE_DATA(nid)->node_start_pfn)
 #define node_end_pfn(nid) pgdat_end_pfn(NODE_DATA(nid))
+static inline spinlock_t *zone_lru_lock(struct zone *zone)
+{
+       return &zone->zone_pgdat->lru_lock;
+}
+
+static inline struct lruvec *node_lruvec(struct pglist_data *pgdat)
+{
+       return &pgdat->lruvec;
+}
 
 static inline unsigned long pgdat_end_pfn(pg_data_t *pgdat)
 {
@@ -760,12 +794,12 @@ extern int init_currently_empty_zone(struct zone *zone, unsigned long start_pfn,
 
 extern void lruvec_init(struct lruvec *lruvec);
 
-static inline struct zone *lruvec_zone(struct lruvec *lruvec)
+static inline struct pglist_data *lruvec_pgdat(struct lruvec *lruvec)
 {
 #ifdef CONFIG_MEMCG
-       return lruvec->zone;
+       return lruvec->pgdat;
 #else
-       return container_of(lruvec, struct zone, lruvec);
+       return container_of(lruvec, struct pglist_data, lruvec);
 #endif
 }
 
index aee2761..f1ea426 100644 (file)
@@ -26,6 +26,7 @@ struct nd_device_driver {
        unsigned long type;
        int (*probe)(struct device *dev);
        int (*remove)(struct device *dev);
+       void (*shutdown)(struct device *dev);
        void (*notify)(struct device *dev, enum nvdimm_event event);
 };
 
@@ -67,7 +68,7 @@ struct nd_namespace_io {
        struct nd_namespace_common common;
        struct resource res;
        resource_size_t size;
-       void __pmem *addr;
+       void *addr;
        struct badblocks bb;
 };
 
index 606137b..5bc0457 100644 (file)
@@ -73,9 +73,9 @@ static inline bool oom_task_origin(const struct task_struct *p)
 extern void mark_oom_victim(struct task_struct *tsk);
 
 #ifdef CONFIG_MMU
-extern void try_oom_reaper(struct task_struct *tsk);
+extern void wake_oom_reaper(struct task_struct *tsk);
 #else
-static inline void try_oom_reaper(struct task_struct *tsk)
+static inline void wake_oom_reaper(struct task_struct *tsk)
 {
 }
 #endif
@@ -107,27 +107,7 @@ extern void oom_killer_enable(void);
 
 extern struct task_struct *find_lock_task_mm(struct task_struct *p);
 
-static inline bool task_will_free_mem(struct task_struct *task)
-{
-       struct signal_struct *sig = task->signal;
-
-       /*
-        * A coredumping process may sleep for an extended period in exit_mm(),
-        * so the oom killer cannot assume that the process will promptly exit
-        * and release memory.
-        */
-       if (sig->flags & SIGNAL_GROUP_COREDUMP)
-               return false;
-
-       if (!(task->flags & PF_EXITING))
-               return false;
-
-       /* Make sure that the whole thread group is going down */
-       if (!thread_group_empty(task) && !(sig->flags & SIGNAL_GROUP_EXIT))
-               return false;
-
-       return true;
-}
+bool task_will_free_mem(struct task_struct *task);
 
 /* sysctls */
 extern int sysctl_oom_dump_tasks;
index 9499481..a3d90b9 100644 (file)
@@ -28,7 +28,10 @@ static inline pfn_t pfn_to_pfn_t(unsigned long pfn)
        return __pfn_to_pfn_t(pfn, 0);
 }
 
-extern pfn_t phys_to_pfn_t(phys_addr_t addr, u64 flags);
+static inline pfn_t phys_to_pfn_t(phys_addr_t addr, u64 flags)
+{
+       return __pfn_to_pfn_t(addr >> PAGE_SHIFT, flags);
+}
 
 static inline bool pfn_t_has_page(pfn_t pfn)
 {
index d921afd..12343ca 100644 (file)
@@ -175,6 +175,8 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev,
 int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev,
                struct device_node *np_config, struct pinctrl_map **map,
                unsigned *num_maps, enum pinctrl_map_type type);
+void pinconf_generic_dt_free_map(struct pinctrl_dev *pctldev,
+               struct pinctrl_map *map, unsigned num_maps);
 
 static inline int pinconf_generic_dt_node_to_map_group(
                struct pinctrl_dev *pctldev, struct device_node *np_config,
index 57d146f..e856c2c 100644 (file)
  * calling these symbols with arch_has_pmem_api() and redirect to the
  * implementation in asm/pmem.h.
  */
-static inline bool __arch_has_wmb_pmem(void)
-{
-       return false;
-}
-
-static inline void arch_wmb_pmem(void)
-{
-       BUG();
-}
-
-static inline void arch_memcpy_to_pmem(void __pmem *dst, const void *src,
-               size_t n)
+static inline void arch_memcpy_to_pmem(void *dst, const void *src, size_t n)
 {
        BUG();
 }
 
-static inline int arch_memcpy_from_pmem(void *dst, const void __pmem *src,
-               size_t n)
+static inline int arch_memcpy_from_pmem(void *dst, const void *src, size_t n)
 {
        BUG();
        return -EFAULT;
 }
 
-static inline size_t arch_copy_from_iter_pmem(void __pmem *addr, size_t bytes,
+static inline size_t arch_copy_from_iter_pmem(void *addr, size_t bytes,
                struct iov_iter *i)
 {
        BUG();
        return 0;
 }
 
-static inline void arch_clear_pmem(void __pmem *addr, size_t size)
+static inline void arch_clear_pmem(void *addr, size_t size)
 {
        BUG();
 }
 
-static inline void arch_wb_cache_pmem(void __pmem *addr, size_t size)
+static inline void arch_wb_cache_pmem(void *addr, size_t size)
 {
        BUG();
 }
 
-static inline void arch_invalidate_pmem(void __pmem *addr, size_t size)
+static inline void arch_invalidate_pmem(void *addr, size_t size)
 {
        BUG();
 }
@@ -77,13 +65,6 @@ static inline bool arch_has_pmem_api(void)
        return IS_ENABLED(CONFIG_ARCH_HAS_PMEM_API);
 }
 
-static inline int default_memcpy_from_pmem(void *dst, void __pmem const *src,
-               size_t size)
-{
-       memcpy(dst, (void __force *) src, size);
-       return 0;
-}
-
 /*
  * memcpy_from_pmem - read from persistent memory with error handling
  * @dst: destination buffer
@@ -92,54 +73,13 @@ static inline int default_memcpy_from_pmem(void *dst, void __pmem const *src,
  *
  * Returns 0 on success negative error code on failure.
  */
-static inline int memcpy_from_pmem(void *dst, void __pmem const *src,
-               size_t size)
+static inline int memcpy_from_pmem(void *dst, void const *src, size_t size)
 {
        if (arch_has_pmem_api())
                return arch_memcpy_from_pmem(dst, src, size);
        else
-               return default_memcpy_from_pmem(dst, src, size);
-}
-
-/**
- * arch_has_wmb_pmem - true if wmb_pmem() ensures durability
- *
- * For a given cpu implementation within an architecture it is possible
- * that wmb_pmem() resolves to a nop.  In the case this returns
- * false, pmem api users are unable to ensure durability and may want to
- * fall back to a different data consistency model, or otherwise notify
- * the user.
- */
-static inline bool arch_has_wmb_pmem(void)
-{
-       return arch_has_pmem_api() && __arch_has_wmb_pmem();
-}
-
-/*
- * These defaults seek to offer decent performance and minimize the
- * window between i/o completion and writes being durable on media.
- * However, it is undefined / architecture specific whether
- * ARCH_MEMREMAP_PMEM + default_memcpy_to_pmem is sufficient for
- * making data durable relative to i/o completion.
- */
-static inline void default_memcpy_to_pmem(void __pmem *dst, const void *src,
-               size_t size)
-{
-       memcpy((void __force *) dst, src, size);
-}
-
-static inline size_t default_copy_from_iter_pmem(void __pmem *addr,
-               size_t bytes, struct iov_iter *i)
-{
-       return copy_from_iter_nocache((void __force *)addr, bytes, i);
-}
-
-static inline void default_clear_pmem(void __pmem *addr, size_t size)
-{
-       if (size == PAGE_SIZE && ((unsigned long)addr & ~PAGE_MASK) == 0)
-               clear_page((void __force *)addr);
-       else
-               memset((void __force *)addr, 0, size);
+               memcpy(dst, src, size);
+       return 0;
 }
 
 /**
@@ -152,29 +92,14 @@ static inline void default_clear_pmem(void __pmem *addr, size_t size)
  * being effectively evicted from, or never written to, the processor
  * cache hierarchy after the copy completes.  After memcpy_to_pmem()
  * data may still reside in cpu or platform buffers, so this operation
- * must be followed by a wmb_pmem().
+ * must be followed by a blkdev_issue_flush() on the pmem block device.
  */
-static inline void memcpy_to_pmem(void __pmem *dst, const void *src, size_t n)
+static inline void memcpy_to_pmem(void *dst, const void *src, size_t n)
 {
        if (arch_has_pmem_api())
                arch_memcpy_to_pmem(dst, src, n);
        else
-               default_memcpy_to_pmem(dst, src, n);
-}
-
-/**
- * wmb_pmem - synchronize writes to persistent memory
- *
- * After a series of memcpy_to_pmem() operations this drains data from
- * cpu write buffers and any platform (memory controller) buffers to
- * ensure that written data is durable on persistent memory media.
- */
-static inline void wmb_pmem(void)
-{
-       if (arch_has_wmb_pmem())
-               arch_wmb_pmem();
-       else
-               wmb();
+               memcpy(dst, src, n);
 }
 
 /**
@@ -184,14 +109,14 @@ static inline void wmb_pmem(void)
  * @i:         iterator with source data
  *
  * Copy data from the iterator 'i' to the PMEM buffer starting at 'addr'.
- * This function requires explicit ordering with a wmb_pmem() call.
+ * See blkdev_issue_flush() note for memcpy_to_pmem().
  */
-static inline size_t copy_from_iter_pmem(void __pmem *addr, size_t bytes,
+static inline size_t copy_from_iter_pmem(void *addr, size_t bytes,
                struct iov_iter *i)
 {
        if (arch_has_pmem_api())
                return arch_copy_from_iter_pmem(addr, bytes, i);
-       return default_copy_from_iter_pmem(addr, bytes, i);
+       return copy_from_iter_nocache(addr, bytes, i);
 }
 
 /**
@@ -200,14 +125,14 @@ static inline size_t copy_from_iter_pmem(void __pmem *addr, size_t bytes,
  * @size:      number of bytes to zero
  *
  * Write zeros into the memory range starting at 'addr' for 'size' bytes.
- * This function requires explicit ordering with a wmb_pmem() call.
+ * See blkdev_issue_flush() note for memcpy_to_pmem().
  */
-static inline void clear_pmem(void __pmem *addr, size_t size)
+static inline void clear_pmem(void *addr, size_t size)
 {
        if (arch_has_pmem_api())
                arch_clear_pmem(addr, size);
        else
-               default_clear_pmem(addr, size);
+               memset(addr, 0, size);
 }
 
 /**
@@ -218,7 +143,7 @@ static inline void clear_pmem(void __pmem *addr, size_t size)
  * For platforms that support clearing poison this flushes any poisoned
  * ranges out of the cache
  */
-static inline void invalidate_pmem(void __pmem *addr, size_t size)
+static inline void invalidate_pmem(void *addr, size_t size)
 {
        if (arch_has_pmem_api())
                arch_invalidate_pmem(addr, size);
@@ -230,9 +155,9 @@ static inline void invalidate_pmem(void __pmem *addr, size_t size)
  * @size:      number of bytes to write back
  *
  * Write back the processor cache range starting at 'addr' for 'size' bytes.
- * This function requires explicit ordering with a wmb_pmem() call.
+ * See blkdev_issue_flush() note for memcpy_to_pmem().
  */
-static inline void wb_cache_pmem(void __pmem *addr, size_t size)
+static inline void wb_cache_pmem(void *addr, size_t size)
 {
        if (arch_has_pmem_api())
                arch_wb_cache_pmem(addr, size);
index 9dfb6bc..8486d27 100644 (file)
@@ -200,8 +200,8 @@ struct mem_dqblk {
        qsize_t dqb_ihardlimit; /* absolute limit on allocated inodes */
        qsize_t dqb_isoftlimit; /* preferred inode limit */
        qsize_t dqb_curinodes;  /* current # allocated inodes */
-       time_t dqb_btime;       /* time limit for excessive disk use */
-       time_t dqb_itime;       /* time limit for excessive inode use */
+       time64_t dqb_btime;     /* time limit for excessive disk use */
+       time64_t dqb_itime;     /* time limit for excessive inode use */
 };
 
 /*
index d99218a..553af29 100644 (file)
@@ -523,6 +523,7 @@ static inline int get_dumpable(struct mm_struct *mm)
 #define MMF_HAS_UPROBES                19      /* has uprobes */
 #define MMF_RECALC_UPROBES     20      /* MMF_HAS_UPROBES can be wrong */
 #define MMF_OOM_REAPED         21      /* mm has been already reaped */
+#define MMF_OOM_NOT_REAPABLE   22      /* mm couldn't be reaped */
 
 #define MMF_INIT_MASK          (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK)
 
@@ -1949,6 +1950,32 @@ static inline int tsk_nr_cpus_allowed(struct task_struct *p)
 #define TNF_FAULT_LOCAL        0x08
 #define TNF_MIGRATE_FAIL 0x10
 
+static inline bool in_vfork(struct task_struct *tsk)
+{
+       bool ret;
+
+       /*
+        * need RCU to access ->real_parent if CLONE_VM was used along with
+        * CLONE_PARENT.
+        *
+        * We check real_parent->mm == tsk->mm because CLONE_VFORK does not
+        * imply CLONE_VM
+        *
+        * CLONE_VFORK can be used with CLONE_PARENT/CLONE_THREAD and thus
+        * ->real_parent is not necessarily the task doing vfork(), so in
+        * theory we can't rely on task_lock() if we want to dereference it.
+        *
+        * And in this case we can't trust the real_parent->mm == tsk->mm
+        * check, it can be false negative. But we do not care, if init or
+        * another oom-unkillable task does this it should blame itself.
+        */
+       rcu_read_lock();
+       ret = tsk->vfork_done && tsk->real_parent->mm == tsk->mm;
+       rcu_read_unlock();
+
+       return ret;
+}
+
 #ifdef CONFIG_NUMA_BALANCING
 extern void task_numa_fault(int last_node, int node, int pages, int flags);
 extern pid_t task_numa_group_id(struct task_struct *p);
index 339ba02..4ad2c5a 100644 (file)
@@ -88,7 +88,8 @@ struct kmem_cache {
 };
 
 static inline void *nearest_obj(struct kmem_cache *cache, struct page *page,
-                               void *x) {
+                               void *x)
+{
        void *object = x - (x - page->s_mem) % cache->size;
        void *last_object = page->s_mem + (cache->num - 1) * cache->size;
 
index 5624c1f..75f56c2 100644 (file)
@@ -104,6 +104,10 @@ struct kmem_cache {
        unsigned int *random_seq;
 #endif
 
+#ifdef CONFIG_KASAN
+       struct kasan_cache kasan_info;
+#endif
+
        struct kmem_cache_node *node[MAX_NUMNODES];
 };
 
@@ -119,15 +123,17 @@ static inline void sysfs_slab_remove(struct kmem_cache *s)
 void object_err(struct kmem_cache *s, struct page *page,
                u8 *object, char *reason);
 
+void *fixup_red_left(struct kmem_cache *s, void *p);
+
 static inline void *nearest_obj(struct kmem_cache *cache, struct page *page,
                                void *x) {
        void *object = x - (x - page_address(page)) % cache->size;
        void *last_object = page_address(page) +
                (page->objects - 1) * cache->size;
-       if (unlikely(object > last_object))
-               return last_object;
-       else
-               return object;
+       void *result = (unlikely(object > last_object)) ? last_object : object;
+
+       result = fixup_red_left(cache, result);
+       return result;
 }
 
 #endif /* _LINUX_SLUB_DEF_H */
index 451771d..7c2d951 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/compiler.h>    /* For __pure */
 #include <linux/types.h>       /* For u32, u64 */
+#include <linux/hash.h>
 
 /*
  * Routines for hashing strings of bytes to a 32-bit hash value.
@@ -34,7 +35,7 @@
  */
 
 /* Hash courtesy of the R5 hash in reiserfs modulo sign bits */
-#define init_name_hash()               0
+#define init_name_hash(salt)           (unsigned long)(salt)
 
 /* partial hash update function. Assume roughly 4 bits per character */
 static inline unsigned long
@@ -45,11 +46,12 @@ partial_name_hash(unsigned long c, unsigned long prevhash)
 
 /*
  * Finally: cut down the number of bits to a int value (and try to avoid
- * losing bits)
+ * losing bits).  This also has the property (wanted by the dcache)
+ * that the msbits make a good hash table index.
  */
 static inline unsigned long end_name_hash(unsigned long hash)
 {
-       return (unsigned int)hash;
+       return __hash_32((unsigned int)hash);
 }
 
 /*
@@ -60,7 +62,7 @@ static inline unsigned long end_name_hash(unsigned long hash)
  *
  * If not set, this falls back to a wrapper around the preceding.
  */
-extern unsigned int __pure full_name_hash(const char *, unsigned int);
+extern unsigned int __pure full_name_hash(const void *salt, const char *, unsigned int);
 
 /*
  * A hash_len is a u64 with the hash of a string in the low
@@ -71,6 +73,6 @@ extern unsigned int __pure full_name_hash(const char *, unsigned int);
 #define hashlen_create(hash, len) ((u64)(len)<<32 | (u32)(hash))
 
 /* Return the "hash_len" (hash and length) of a null-terminated string */
-extern u64 __pure hashlen_string(const char *name);
+extern u64 __pure hashlen_string(const void *salt, const char *name);
 
 #endif /* __LINUX_STRINGHASH_H */
index 91d5a5d..d039320 100644 (file)
@@ -172,12 +172,12 @@ extern void unix_gid_cache_destroy(struct net *net);
  */
 static inline unsigned long hash_str(char const *name, int bits)
 {
-       return hashlen_hash(hashlen_string(name)) >> (32 - bits);
+       return hashlen_hash(hashlen_string(NULL, name)) >> (32 - bits);
 }
 
 static inline unsigned long hash_mem(char const *buf, int length, int bits)
 {
-       return full_name_hash(buf, length) >> (32 - bits);
+       return full_name_hash(NULL, buf, length) >> (32 - bits);
 }
 
 #endif /* __KERNEL__ */
index 0af2bb2..b17cc48 100644 (file)
@@ -157,15 +157,6 @@ enum {
 #define SWAP_CLUSTER_MAX 32UL
 #define COMPACT_CLUSTER_MAX SWAP_CLUSTER_MAX
 
-/*
- * Ratio between zone->managed_pages and the "gap" that above the per-zone
- * "high_wmark". While balancing nodes, We allow kswapd to shrink zones that
- * do not meet the (high_wmark + gap) watermark, even which already met the
- * high_wmark, in order to provide better per-zone lru behavior. We are ok to
- * spend not more than 1% of the memory for this zone balancing "gap".
- */
-#define KSWAPD_ZONE_BALANCE_GAP_RATIO 100
-
 #define SWAP_MAP_MAX   0x3e    /* Max duplication count, in first swap_map */
 #define SWAP_MAP_BAD   0x3f    /* Note pageblock is bad, in first swap_map */
 #define SWAP_HAS_CACHE 0x40    /* Flag page is cached, in first swap_map */
@@ -317,6 +308,7 @@ extern void lru_cache_add_active_or_unevictable(struct page *page,
 
 /* linux/mm/vmscan.c */
 extern unsigned long zone_reclaimable_pages(struct zone *zone);
+extern unsigned long pgdat_reclaimable_pages(struct pglist_data *pgdat);
 extern unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
                                        gfp_t gfp_mask, nodemask_t *mask);
 extern int __isolate_lru_page(struct page *page, isolate_mode_t mode);
@@ -324,9 +316,9 @@ extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
                                                  unsigned long nr_pages,
                                                  gfp_t gfp_mask,
                                                  bool may_swap);
-extern unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
+extern unsigned long mem_cgroup_shrink_node(struct mem_cgroup *mem,
                                                gfp_t gfp_mask, bool noswap,
-                                               struct zone *zone,
+                                               pg_data_t *pgdat,
                                                unsigned long *nr_scanned);
 extern unsigned long shrink_all_memory(unsigned long nr_pages);
 extern int vm_swappiness;
@@ -334,13 +326,14 @@ extern int remove_mapping(struct address_space *mapping, struct page *page);
 extern unsigned long vm_total_pages;
 
 #ifdef CONFIG_NUMA
-extern int zone_reclaim_mode;
+extern int node_reclaim_mode;
 extern int sysctl_min_unmapped_ratio;
 extern int sysctl_min_slab_ratio;
-extern int zone_reclaim(struct zone *, gfp_t, unsigned int);
+extern int node_reclaim(struct pglist_data *, gfp_t, unsigned int);
 #else
-#define zone_reclaim_mode 0
-static inline int zone_reclaim(struct zone *z, gfp_t mask, unsigned int order)
+#define node_reclaim_mode 0
+static inline int node_reclaim(struct pglist_data *pgdat, gfp_t mask,
+                               unsigned int order)
 {
        return 0;
 }
index afce692..cb0775e 100644 (file)
@@ -54,7 +54,7 @@ int arch_update_cpu_topology(void);
 /*
  * If the distance between nodes in a system is larger than RECLAIM_DISTANCE
  * (in whatever arch specific measurement units returned by node_distance())
- * and zone_reclaim_mode is enabled then the VM will only call zone_reclaim()
+ * and node_reclaim_mode is enabled then the VM will only call node_reclaim()
  * on nodes within this distance.
  */
 #define RECLAIM_DISTANCE 30
index 4260417..4d6ec58 100644 (file)
 
 enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
                FOR_ALL_ZONES(PGALLOC),
+               FOR_ALL_ZONES(ALLOCSTALL),
+               FOR_ALL_ZONES(PGSCAN_SKIP),
                PGFREE, PGACTIVATE, PGDEACTIVATE,
                PGFAULT, PGMAJFAULT,
                PGLAZYFREED,
-               FOR_ALL_ZONES(PGREFILL),
-               FOR_ALL_ZONES(PGSTEAL_KSWAPD),
-               FOR_ALL_ZONES(PGSTEAL_DIRECT),
-               FOR_ALL_ZONES(PGSCAN_KSWAPD),
-               FOR_ALL_ZONES(PGSCAN_DIRECT),
+               PGREFILL,
+               PGSTEAL_KSWAPD,
+               PGSTEAL_DIRECT,
+               PGSCAN_KSWAPD,
+               PGSCAN_DIRECT,
                PGSCAN_DIRECT_THROTTLE,
 #ifdef CONFIG_NUMA
                PGSCAN_ZONE_RECLAIM_FAILED,
 #endif
                PGINODESTEAL, SLABS_SCANNED, KSWAPD_INODESTEAL,
                KSWAPD_LOW_WMARK_HIT_QUICKLY, KSWAPD_HIGH_WMARK_HIT_QUICKLY,
-               PAGEOUTRUN, ALLOCSTALL, PGROTATED,
+               PAGEOUTRUN, PGROTATED,
                DROP_PAGECACHE, DROP_SLAB,
 #ifdef CONFIG_NUMA_BALANCING
                NUMA_PTE_UPDATES,
index d2da8e0..6137719 100644 (file)
@@ -101,25 +101,42 @@ static inline void vm_events_fold_cpu(int cpu)
 #define count_vm_vmacache_event(x) do {} while (0)
 #endif
 
-#define __count_zone_vm_events(item, zone, delta) \
-               __count_vm_events(item##_NORMAL - ZONE_NORMAL + \
-               zone_idx(zone), delta)
+#define __count_zid_vm_events(item, zid, delta) \
+       __count_vm_events(item##_NORMAL - ZONE_NORMAL + zid, delta)
 
 /*
- * Zone based page accounting with per cpu differentials.
+ * Zone and node-based page accounting with per cpu differentials.
  */
-extern atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS];
+extern atomic_long_t vm_zone_stat[NR_VM_ZONE_STAT_ITEMS];
+extern atomic_long_t vm_node_stat[NR_VM_NODE_STAT_ITEMS];
 
 static inline void zone_page_state_add(long x, struct zone *zone,
                                 enum zone_stat_item item)
 {
        atomic_long_add(x, &zone->vm_stat[item]);
-       atomic_long_add(x, &vm_stat[item]);
+       atomic_long_add(x, &vm_zone_stat[item]);
+}
+
+static inline void node_page_state_add(long x, struct pglist_data *pgdat,
+                                enum node_stat_item item)
+{
+       atomic_long_add(x, &pgdat->vm_stat[item]);
+       atomic_long_add(x, &vm_node_stat[item]);
 }
 
 static inline unsigned long global_page_state(enum zone_stat_item item)
 {
-       long x = atomic_long_read(&vm_stat[item]);
+       long x = atomic_long_read(&vm_zone_stat[item]);
+#ifdef CONFIG_SMP
+       if (x < 0)
+               x = 0;
+#endif
+       return x;
+}
+
+static inline unsigned long global_node_page_state(enum node_stat_item item)
+{
+       long x = atomic_long_read(&vm_node_stat[item]);
 #ifdef CONFIG_SMP
        if (x < 0)
                x = 0;
@@ -160,32 +177,61 @@ static inline unsigned long zone_page_state_snapshot(struct zone *zone,
        return x;
 }
 
-#ifdef CONFIG_NUMA
+static inline unsigned long node_page_state_snapshot(pg_data_t *pgdat,
+                                       enum node_stat_item item)
+{
+       long x = atomic_long_read(&pgdat->vm_stat[item]);
 
-extern unsigned long node_page_state(int node, enum zone_stat_item item);
+#ifdef CONFIG_SMP
+       int cpu;
+       for_each_online_cpu(cpu)
+               x += per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->vm_node_stat_diff[item];
 
-#else
+       if (x < 0)
+               x = 0;
+#endif
+       return x;
+}
 
-#define node_page_state(node, item) global_page_state(item)
 
+#ifdef CONFIG_NUMA
+extern unsigned long sum_zone_node_page_state(int node,
+                                               enum zone_stat_item item);
+extern unsigned long node_page_state(struct pglist_data *pgdat,
+                                               enum node_stat_item item);
+#else
+#define sum_zone_node_page_state(node, item) global_page_state(item)
+#define node_page_state(node, item) global_node_page_state(item)
 #endif /* CONFIG_NUMA */
 
 #define add_zone_page_state(__z, __i, __d) mod_zone_page_state(__z, __i, __d)
 #define sub_zone_page_state(__z, __i, __d) mod_zone_page_state(__z, __i, -(__d))
+#define add_node_page_state(__p, __i, __d) mod_node_page_state(__p, __i, __d)
+#define sub_node_page_state(__p, __i, __d) mod_node_page_state(__p, __i, -(__d))
 
 #ifdef CONFIG_SMP
 void __mod_zone_page_state(struct zone *, enum zone_stat_item item, long);
 void __inc_zone_page_state(struct page *, enum zone_stat_item);
 void __dec_zone_page_state(struct page *, enum zone_stat_item);
 
+void __mod_node_page_state(struct pglist_data *, enum node_stat_item item, long);
+void __inc_node_page_state(struct page *, enum node_stat_item);
+void __dec_node_page_state(struct page *, enum node_stat_item);
+
 void mod_zone_page_state(struct zone *, enum zone_stat_item, long);
 void inc_zone_page_state(struct page *, enum zone_stat_item);
 void dec_zone_page_state(struct page *, enum zone_stat_item);
 
-extern void inc_zone_state(struct zone *, enum zone_stat_item);
+void mod_node_page_state(struct pglist_data *, enum node_stat_item, long);
+void inc_node_page_state(struct page *, enum node_stat_item);
+void dec_node_page_state(struct page *, enum node_stat_item);
+
+extern void inc_node_state(struct pglist_data *, enum node_stat_item);
 extern void __inc_zone_state(struct zone *, enum zone_stat_item);
+extern void __inc_node_state(struct pglist_data *, enum node_stat_item);
 extern void dec_zone_state(struct zone *, enum zone_stat_item);
 extern void __dec_zone_state(struct zone *, enum zone_stat_item);
+extern void __dec_node_state(struct pglist_data *, enum node_stat_item);
 
 void quiet_vmstat(void);
 void cpu_vm_stats_fold(int cpu);
@@ -213,16 +259,34 @@ static inline void __mod_zone_page_state(struct zone *zone,
        zone_page_state_add(delta, zone, item);
 }
 
+static inline void __mod_node_page_state(struct pglist_data *pgdat,
+                       enum node_stat_item item, int delta)
+{
+       node_page_state_add(delta, pgdat, item);
+}
+
 static inline void __inc_zone_state(struct zone *zone, enum zone_stat_item item)
 {
        atomic_long_inc(&zone->vm_stat[item]);
-       atomic_long_inc(&vm_stat[item]);
+       atomic_long_inc(&vm_zone_stat[item]);
+}
+
+static inline void __inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
+{
+       atomic_long_inc(&pgdat->vm_stat[item]);
+       atomic_long_inc(&vm_node_stat[item]);
 }
 
 static inline void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
 {
        atomic_long_dec(&zone->vm_stat[item]);
-       atomic_long_dec(&vm_stat[item]);
+       atomic_long_dec(&vm_zone_stat[item]);
+}
+
+static inline void __dec_node_state(struct pglist_data *pgdat, enum node_stat_item item)
+{
+       atomic_long_dec(&pgdat->vm_stat[item]);
+       atomic_long_dec(&vm_node_stat[item]);
 }
 
 static inline void __inc_zone_page_state(struct page *page,
@@ -231,12 +295,26 @@ static inline void __inc_zone_page_state(struct page *page,
        __inc_zone_state(page_zone(page), item);
 }
 
+static inline void __inc_node_page_state(struct page *page,
+                       enum node_stat_item item)
+{
+       __inc_node_state(page_pgdat(page), item);
+}
+
+
 static inline void __dec_zone_page_state(struct page *page,
                        enum zone_stat_item item)
 {
        __dec_zone_state(page_zone(page), item);
 }
 
+static inline void __dec_node_page_state(struct page *page,
+                       enum node_stat_item item)
+{
+       __dec_node_state(page_pgdat(page), item);
+}
+
+
 /*
  * We only use atomic operations to update counters. So there is no need to
  * disable interrupts.
@@ -245,7 +323,12 @@ static inline void __dec_zone_page_state(struct page *page,
 #define dec_zone_page_state __dec_zone_page_state
 #define mod_zone_page_state __mod_zone_page_state
 
+#define inc_node_page_state __inc_node_page_state
+#define dec_node_page_state __dec_node_page_state
+#define mod_node_page_state __mod_node_page_state
+
 #define inc_zone_state __inc_zone_state
+#define inc_node_state __inc_node_state
 #define dec_zone_state __dec_zone_state
 
 #define set_pgdat_percpu_threshold(pgdat, callback) { }
index 717e614..fc1e16c 100644 (file)
@@ -320,7 +320,7 @@ void laptop_mode_timer_fn(unsigned long data);
 static inline void laptop_sync_completion(void) { }
 #endif
 void throttle_vm_writeout(gfp_t gfp_mask);
-bool zone_dirty_ok(struct zone *zone);
+bool node_dirty_ok(struct pglist_data *pgdat);
 int wb_domain_init(struct wb_domain *dom, gfp_t gfp);
 #ifdef CONFIG_CGROUP_WRITEBACK
 void wb_domain_exit(struct wb_domain *dom);
index 36e2d6f..c2ba402 100644 (file)
@@ -226,26 +226,26 @@ TRACE_EVENT(mm_compaction_try_to_compact_pages,
        TP_PROTO(
                int order,
                gfp_t gfp_mask,
-               enum migrate_mode mode),
+               int prio),
 
-       TP_ARGS(order, gfp_mask, mode),
+       TP_ARGS(order, gfp_mask, prio),
 
        TP_STRUCT__entry(
                __field(int, order)
                __field(gfp_t, gfp_mask)
-               __field(enum migrate_mode, mode)
+               __field(int, prio)
        ),
 
        TP_fast_assign(
                __entry->order = order;
                __entry->gfp_mask = gfp_mask;
-               __entry->mode = mode;
+               __entry->prio = prio;
        ),
 
-       TP_printk("order=%d gfp_mask=0x%x mode=%d",
+       TP_printk("order=%d gfp_mask=0x%x priority=%d",
                __entry->order,
                __entry->gfp_mask,
-               (int)__entry->mode)
+               __entry->prio)
 );
 
 DECLARE_EVENT_CLASS(mm_compaction_suitable_template,
index 43cedbf..5a81ab4 100644 (file)
@@ -11,6 +11,7 @@
 
 #define __def_gfpflag_names                                            \
        {(unsigned long)GFP_TRANSHUGE,          "GFP_TRANSHUGE"},       \
+       {(unsigned long)GFP_TRANSHUGE_LIGHT,    "GFP_TRANSHUGE_LIGHT"}, \
        {(unsigned long)GFP_HIGHUSER_MOVABLE,   "GFP_HIGHUSER_MOVABLE"},\
        {(unsigned long)GFP_HIGHUSER,           "GFP_HIGHUSER"},        \
        {(unsigned long)GFP_USER,               "GFP_USER"},            \
index 0101ef3..c88fd09 100644 (file)
@@ -55,21 +55,23 @@ TRACE_EVENT(mm_vmscan_kswapd_sleep,
 
 TRACE_EVENT(mm_vmscan_kswapd_wake,
 
-       TP_PROTO(int nid, int order),
+       TP_PROTO(int nid, int zid, int order),
 
-       TP_ARGS(nid, order),
+       TP_ARGS(nid, zid, order),
 
        TP_STRUCT__entry(
                __field(        int,    nid     )
+               __field(        int,    zid     )
                __field(        int,    order   )
        ),
 
        TP_fast_assign(
                __entry->nid    = nid;
+               __entry->zid    = zid;
                __entry->order  = order;
        ),
 
-       TP_printk("nid=%d order=%d", __entry->nid, __entry->order)
+       TP_printk("nid=%d zid=%d order=%d", __entry->nid, __entry->zid, __entry->order)
 );
 
 TRACE_EVENT(mm_vmscan_wakeup_kswapd,
@@ -98,47 +100,50 @@ TRACE_EVENT(mm_vmscan_wakeup_kswapd,
 
 DECLARE_EVENT_CLASS(mm_vmscan_direct_reclaim_begin_template,
 
-       TP_PROTO(int order, int may_writepage, gfp_t gfp_flags),
+       TP_PROTO(int order, int may_writepage, gfp_t gfp_flags, int classzone_idx),
 
-       TP_ARGS(order, may_writepage, gfp_flags),
+       TP_ARGS(order, may_writepage, gfp_flags, classzone_idx),
 
        TP_STRUCT__entry(
                __field(        int,    order           )
                __field(        int,    may_writepage   )
                __field(        gfp_t,  gfp_flags       )
+               __field(        int,    classzone_idx   )
        ),
 
        TP_fast_assign(
                __entry->order          = order;
                __entry->may_writepage  = may_writepage;
                __entry->gfp_flags      = gfp_flags;
+               __entry->classzone_idx  = classzone_idx;
        ),
 
-       TP_printk("order=%d may_writepage=%d gfp_flags=%s",
+       TP_printk("order=%d may_writepage=%d gfp_flags=%s classzone_idx=%d",
                __entry->order,
                __entry->may_writepage,
-               show_gfp_flags(__entry->gfp_flags))
+               show_gfp_flags(__entry->gfp_flags),
+               __entry->classzone_idx)
 );
 
 DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_direct_reclaim_begin,
 
-       TP_PROTO(int order, int may_writepage, gfp_t gfp_flags),
+       TP_PROTO(int order, int may_writepage, gfp_t gfp_flags, int classzone_idx),
 
-       TP_ARGS(order, may_writepage, gfp_flags)
+       TP_ARGS(order, may_writepage, gfp_flags, classzone_idx)
 );
 
 DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_memcg_reclaim_begin,
 
-       TP_PROTO(int order, int may_writepage, gfp_t gfp_flags),
+       TP_PROTO(int order, int may_writepage, gfp_t gfp_flags, int classzone_idx),
 
-       TP_ARGS(order, may_writepage, gfp_flags)
+       TP_ARGS(order, may_writepage, gfp_flags, classzone_idx)
 );
 
 DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_memcg_softlimit_reclaim_begin,
 
-       TP_PROTO(int order, int may_writepage, gfp_t gfp_flags),
+       TP_PROTO(int order, int may_writepage, gfp_t gfp_flags, int classzone_idx),
 
-       TP_ARGS(order, may_writepage, gfp_flags)
+       TP_ARGS(order, may_writepage, gfp_flags, classzone_idx)
 );
 
 DECLARE_EVENT_CLASS(mm_vmscan_direct_reclaim_end_template,
@@ -266,16 +271,18 @@ TRACE_EVENT(mm_shrink_slab_end,
 
 DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template,
 
-       TP_PROTO(int order,
+       TP_PROTO(int classzone_idx,
+               int order,
                unsigned long nr_requested,
                unsigned long nr_scanned,
                unsigned long nr_taken,
                isolate_mode_t isolate_mode,
                int file),
 
-       TP_ARGS(order, nr_requested, nr_scanned, nr_taken, isolate_mode, file),
+       TP_ARGS(classzone_idx, order, nr_requested, nr_scanned, nr_taken, isolate_mode, file),
 
        TP_STRUCT__entry(
+               __field(int, classzone_idx)
                __field(int, order)
                __field(unsigned long, nr_requested)
                __field(unsigned long, nr_scanned)
@@ -285,6 +292,7 @@ DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template,
        ),
 
        TP_fast_assign(
+               __entry->classzone_idx = classzone_idx;
                __entry->order = order;
                __entry->nr_requested = nr_requested;
                __entry->nr_scanned = nr_scanned;
@@ -293,8 +301,9 @@ DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template,
                __entry->file = file;
        ),
 
-       TP_printk("isolate_mode=%d order=%d nr_requested=%lu nr_scanned=%lu nr_taken=%lu file=%d",
+       TP_printk("isolate_mode=%d classzone=%d order=%d nr_requested=%lu nr_scanned=%lu nr_taken=%lu file=%d",
                __entry->isolate_mode,
+               __entry->classzone_idx,
                __entry->order,
                __entry->nr_requested,
                __entry->nr_scanned,
@@ -304,27 +313,29 @@ DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template,
 
 DEFINE_EVENT(mm_vmscan_lru_isolate_template, mm_vmscan_lru_isolate,
 
-       TP_PROTO(int order,
+       TP_PROTO(int classzone_idx,
+               int order,
                unsigned long nr_requested,
                unsigned long nr_scanned,
                unsigned long nr_taken,
                isolate_mode_t isolate_mode,
                int file),
 
-       TP_ARGS(order, nr_requested, nr_scanned, nr_taken, isolate_mode, file)
+       TP_ARGS(classzone_idx, order, nr_requested, nr_scanned, nr_taken, isolate_mode, file)
 
 );
 
 DEFINE_EVENT(mm_vmscan_lru_isolate_template, mm_vmscan_memcg_isolate,
 
-       TP_PROTO(int order,
+       TP_PROTO(int classzone_idx,
+               int order,
                unsigned long nr_requested,
                unsigned long nr_scanned,
                unsigned long nr_taken,
                isolate_mode_t isolate_mode,
                int file),
 
-       TP_ARGS(order, nr_requested, nr_scanned, nr_taken, isolate_mode, file)
+       TP_ARGS(classzone_idx, order, nr_requested, nr_scanned, nr_taken, isolate_mode, file)
 
 );
 
@@ -352,15 +363,14 @@ TRACE_EVENT(mm_vmscan_writepage,
 
 TRACE_EVENT(mm_vmscan_lru_shrink_inactive,
 
-       TP_PROTO(struct zone *zone,
+       TP_PROTO(int nid,
                unsigned long nr_scanned, unsigned long nr_reclaimed,
                int priority, int file),
 
-       TP_ARGS(zone, nr_scanned, nr_reclaimed, priority, file),
+       TP_ARGS(nid, nr_scanned, nr_reclaimed, priority, file),
 
        TP_STRUCT__entry(
                __field(int, nid)
-               __field(int, zid)
                __field(unsigned long, nr_scanned)
                __field(unsigned long, nr_reclaimed)
                __field(int, priority)
@@ -368,16 +378,15 @@ TRACE_EVENT(mm_vmscan_lru_shrink_inactive,
        ),
 
        TP_fast_assign(
-               __entry->nid = zone_to_nid(zone);
-               __entry->zid = zone_idx(zone);
+               __entry->nid = nid;
                __entry->nr_scanned = nr_scanned;
                __entry->nr_reclaimed = nr_reclaimed;
                __entry->priority = priority;
                __entry->reclaim_flags = trace_shrink_flags(file);
        ),
 
-       TP_printk("nid=%d zid=%d nr_scanned=%ld nr_reclaimed=%ld priority=%d flags=%s",
-               __entry->nid, __entry->zid,
+       TP_printk("nid=%d nr_scanned=%ld nr_reclaimed=%ld priority=%d flags=%s",
+               __entry->nid,
                __entry->nr_scanned, __entry->nr_reclaimed,
                __entry->priority,
                show_reclaim_flags(__entry->reclaim_flags))
index 531f581..2ccd9cc 100644 (file)
@@ -412,11 +412,11 @@ TRACE_EVENT(global_dirty_state,
        ),
 
        TP_fast_assign(
-               __entry->nr_dirty       = global_page_state(NR_FILE_DIRTY);
-               __entry->nr_writeback   = global_page_state(NR_WRITEBACK);
-               __entry->nr_unstable    = global_page_state(NR_UNSTABLE_NFS);
-               __entry->nr_dirtied     = global_page_state(NR_DIRTIED);
-               __entry->nr_written     = global_page_state(NR_WRITTEN);
+               __entry->nr_dirty       = global_node_page_state(NR_FILE_DIRTY);
+               __entry->nr_writeback   = global_node_page_state(NR_WRITEBACK);
+               __entry->nr_unstable    = global_node_page_state(NR_UNSTABLE_NFS);
+               __entry->nr_dirtied     = global_node_page_state(NR_DIRTIED);
+               __entry->nr_written     = global_node_page_state(NR_WRITTEN);
                __entry->background_thresh = background_thresh;
                __entry->dirty_thresh   = dirty_thresh;
                __entry->dirty_limit    = global_wb_domain.dirty_limit;
index 309915f..ba5a8c7 100644 (file)
@@ -298,6 +298,7 @@ struct nd_cmd_pkg {
 #define NVDIMM_FAMILY_INTEL 0
 #define NVDIMM_FAMILY_HPE1 1
 #define NVDIMM_FAMILY_HPE2 2
+#define NVDIMM_FAMILY_MSFT 3
 
 #define ND_IOCTL_CALL                  _IOWR(ND_IOCTL, ND_CMD_CALL,\
                                        struct nd_cmd_pkg)
index 5040579..46f817a 100644 (file)
@@ -852,8 +852,8 @@ config LOG_CPU_MAX_BUF_SHIFT
          used as it forces an exact (power of two) size of the ring buffer.
 
          The number of possible CPUs is used for this computation ignoring
-         hotplugging making the compuation optimal for the the worst case
-         scenerio while allowing a simple algorithm to be used from bootup.
+         hotplugging making the computation optimal for the worst case
+         scenario while allowing a simple algorithm to be used from bootup.
 
          Examples shift values and their meaning:
                     17 => 128 KB for each CPU
index 73e93e5..c7fd277 100644 (file)
@@ -1034,15 +1034,6 @@ static void cpuset_change_task_nodemask(struct task_struct *tsk,
 {
        bool need_loop;
 
-       /*
-        * Allow tasks that have access to memory reserves because they have
-        * been OOM killed to get memory anywhere.
-        */
-       if (unlikely(test_thread_flag(TIF_MEMDIE)))
-               return;
-       if (current->flags & PF_EXITING) /* Let dying task have memory */
-               return;
-
        task_lock(tsk);
        /*
         * Determine if a loop is necessary if another thread is doing
index de21f25..52e725d 100644 (file)
@@ -165,20 +165,12 @@ static unsigned long *alloc_thread_stack_node(struct task_struct *tsk,
        struct page *page = alloc_pages_node(node, THREADINFO_GFP,
                                             THREAD_SIZE_ORDER);
 
-       if (page)
-               memcg_kmem_update_page_stat(page, MEMCG_KERNEL_STACK,
-                                           1 << THREAD_SIZE_ORDER);
-
        return page ? page_address(page) : NULL;
 }
 
 static inline void free_thread_stack(unsigned long *stack)
 {
-       struct page *page = virt_to_page(stack);
-
-       memcg_kmem_update_page_stat(page, MEMCG_KERNEL_STACK,
-                                   -(1 << THREAD_SIZE_ORDER));
-       __free_pages(page, THREAD_SIZE_ORDER);
+       __free_pages(virt_to_page(stack), THREAD_SIZE_ORDER);
 }
 # else
 static struct kmem_cache *thread_stack_cache;
@@ -223,9 +215,15 @@ static struct kmem_cache *mm_cachep;
 
 static void account_kernel_stack(unsigned long *stack, int account)
 {
-       struct zone *zone = page_zone(virt_to_page(stack));
+       /* All stack pages are in the same zone and belong to the same memcg. */
+       struct page *first_page = virt_to_page(stack);
+
+       mod_zone_page_state(page_zone(first_page), NR_KERNEL_STACK_KB,
+                           THREAD_SIZE / 1024 * account);
 
-       mod_zone_page_state(zone, NR_KERNEL_STACK, account);
+       memcg_kmem_update_page_stat(
+               first_page, MEMCG_KERNEL_STACK_KB,
+               account * (THREAD_SIZE / 1024));
 }
 
 void free_task(struct task_struct *tsk)
index a8900a3..6f56a9e 100644 (file)
@@ -42,7 +42,7 @@ bool freezing_slow_path(struct task_struct *p)
        if (p->flags & (PF_NOFREEZE | PF_SUSPEND_TASK))
                return false;
 
-       if (test_thread_flag(TIF_MEMDIE))
+       if (test_tsk_thread_flag(p, TIF_MEMDIE))
                return false;
 
        if (pm_nosig_freezing || cgroup_freezing(p))
index 0175321..251d16b 100644 (file)
@@ -169,12 +169,6 @@ void devm_memunmap(struct device *dev, void *addr)
 }
 EXPORT_SYMBOL(devm_memunmap);
 
-pfn_t phys_to_pfn_t(phys_addr_t addr, u64 flags)
-{
-       return __pfn_to_pfn_t(addr >> PAGE_SHIFT, flags);
-}
-EXPORT_SYMBOL(phys_to_pfn_t);
-
 #ifdef CONFIG_ZONE_DEVICE
 static DEFINE_MUTEX(pgmap_lock);
 static RADIX_TREE(pgmap_radix, GFP_KERNEL);
@@ -308,12 +302,6 @@ void *devm_memremap_pages(struct device *dev, struct resource *res,
        if (is_ram == REGION_INTERSECTS)
                return __va(res->start);
 
-       if (altmap && !IS_ENABLED(CONFIG_SPARSEMEM_VMEMMAP)) {
-               dev_err(dev, "%s: altmap requires CONFIG_SPARSEMEM_VMEMMAP=y\n",
-                               __func__);
-               return ERR_PTR(-ENXIO);
-       }
-
        if (!ref)
                return ERR_PTR(-EINVAL);
 
@@ -401,7 +389,6 @@ void vmem_altmap_free(struct vmem_altmap *altmap, unsigned long nr_pfns)
        altmap->alloc -= nr_pfns;
 }
 
-#ifdef CONFIG_SPARSEMEM_VMEMMAP
 struct vmem_altmap *to_vmem_altmap(unsigned long memmap_start)
 {
        /*
@@ -427,5 +414,4 @@ struct vmem_altmap *to_vmem_altmap(unsigned long memmap_start)
 
        return pgmap ? pgmap->altmap : NULL;
 }
-#endif /* CONFIG_SPARSEMEM_VMEMMAP */
 #endif /* CONFIG_ZONE_DEVICE */
index d90df92..9a0178c 100644 (file)
@@ -1627,11 +1627,11 @@ static unsigned long minimum_image_size(unsigned long saveable)
        unsigned long size;
 
        size = global_page_state(NR_SLAB_RECLAIMABLE)
-               + global_page_state(NR_ACTIVE_ANON)
-               + global_page_state(NR_INACTIVE_ANON)
-               + global_page_state(NR_ACTIVE_FILE)
-               + global_page_state(NR_INACTIVE_FILE)
-               - global_page_state(NR_FILE_MAPPED);
+               + global_node_page_state(NR_ACTIVE_ANON)
+               + global_node_page_state(NR_INACTIVE_ANON)
+               + global_node_page_state(NR_ACTIVE_FILE)
+               + global_node_page_state(NR_INACTIVE_FILE)
+               - global_node_page_state(NR_FILE_MAPPED);
 
        return saveable <= size ? 0 : saveable - size;
 }
index 60cdf63..d4de339 100644 (file)
@@ -3177,9 +3177,8 @@ void show_regs_print_info(const char *log_lvl)
 {
        dump_stack_print_info(log_lvl);
 
-       printk("%stask: %p ti: %p task.ti: %p\n",
-              log_lvl, current, current_thread_info(),
-              task_thread_info(current));
+       printk("%stask: %p task.stack: %p\n",
+              log_lvl, current, task_stack_page(current));
 }
 
 #endif
index 35f0dcb..5395463 100644 (file)
@@ -1508,8 +1508,8 @@ static struct ctl_table vm_table[] = {
 #ifdef CONFIG_NUMA
        {
                .procname       = "zone_reclaim_mode",
-               .data           = &zone_reclaim_mode,
-               .maxlen         = sizeof(zone_reclaim_mode),
+               .data           = &node_reclaim_mode,
+               .maxlen         = sizeof(node_reclaim_mode),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
                .extra1         = &zero,
index 67d8c68..bd38aab 100644 (file)
@@ -5,9 +5,9 @@ if HAVE_ARCH_KASAN
 
 config KASAN
        bool "KASan: runtime memory debugger"
-       depends on SLUB_DEBUG || (SLAB && !DEBUG_SLAB)
+       depends on SLUB || (SLAB && !DEBUG_SLAB)
        select CONSTRUCTORS
-       select STACKDEPOT if SLAB
+       select STACKDEPOT
        help
          Enables kernel address sanitizer - runtime memory debugger,
          designed to find out-of-bounds accesses and use-after-free bugs.
index d67c828..9e8c738 100644 (file)
@@ -144,7 +144,7 @@ static size_t copy_page_to_iter_iovec(struct page *page, size_t offset, size_t b
        buf = iov->iov_base + skip;
        copy = min(bytes, iov->iov_len - skip);
 
-       if (!fault_in_pages_writeable(buf, copy)) {
+       if (IS_ENABLED(CONFIG_HIGHMEM) && !fault_in_pages_writeable(buf, copy)) {
                kaddr = kmap_atomic(page);
                from = kaddr + offset;
 
@@ -175,6 +175,7 @@ static size_t copy_page_to_iter_iovec(struct page *page, size_t offset, size_t b
                copy = min(bytes, iov->iov_len - skip);
        }
        /* Too bad - revert to non-atomic kmap */
+
        kaddr = kmap(page);
        from = kaddr + offset;
        left = __copy_to_user(buf, from, copy);
@@ -193,6 +194,7 @@ static size_t copy_page_to_iter_iovec(struct page *page, size_t offset, size_t b
                bytes -= copy;
        }
        kunmap(page);
+
 done:
        if (skip == iov->iov_len) {
                iov++;
@@ -225,7 +227,7 @@ static size_t copy_page_from_iter_iovec(struct page *page, size_t offset, size_t
        buf = iov->iov_base + skip;
        copy = min(bytes, iov->iov_len - skip);
 
-       if (!fault_in_pages_readable(buf, copy)) {
+       if (IS_ENABLED(CONFIG_HIGHMEM) && !fault_in_pages_readable(buf, copy)) {
                kaddr = kmap_atomic(page);
                to = kaddr + offset;
 
@@ -256,6 +258,7 @@ static size_t copy_page_from_iter_iovec(struct page *page, size_t offset, size_t
                copy = min(bytes, iov->iov_len - skip);
        }
        /* Too bad - revert to non-atomic kmap */
+
        kaddr = kmap(page);
        to = kaddr + offset;
        left = __copy_from_user(to, buf, copy);
@@ -274,6 +277,7 @@ static size_t copy_page_from_iter_iovec(struct page *page, size_t offset, size_t
                bytes -= copy;
        }
        kunmap(page);
+
 done:
        if (skip == iov->iov_len) {
                iov++;
index 53ad6c0..60f77f1 100644 (file)
@@ -242,6 +242,7 @@ depot_stack_handle_t depot_save_stack(struct stack_trace *trace,
                 */
                alloc_flags &= ~GFP_ZONEMASK;
                alloc_flags &= (GFP_ATOMIC | GFP_KERNEL);
+               alloc_flags |= __GFP_NOWARN;
                page = alloc_pages(alloc_flags, STACK_ALLOC_ORDER);
                if (page)
                        prealloc = page_address(page);
index c9549c8..66c5fc8 100644 (file)
@@ -155,8 +155,8 @@ test_hash_init(void)
                buf[j] = '\0';
 
                for (i = 0; i <= j; i++) {
-                       u64 hashlen = hashlen_string(buf+i);
-                       u32 h0 = full_name_hash(buf+i, j-i);
+                       u64 hashlen = hashlen_string(buf+i, buf+i);
+                       u32 h0 = full_name_hash(buf+i, buf+i, j-i);
 
                        /* Check that hashlen_string gets the length right */
                        if (hashlen_len(hashlen) != j-i) {
index 3c81803..c083784 100644 (file)
@@ -681,7 +681,7 @@ config IDLE_PAGE_TRACKING
          See Documentation/vm/idle_page_tracking.txt for more details.
 
 config ZONE_DEVICE
-       bool "Device memory (pmem, etc...) hotplug support" if EXPERT
+       bool "Device memory (pmem, etc...) hotplug support"
        depends on MEMORY_HOTPLUG
        depends on MEMORY_HOTREMOVE
        depends on SPARSEMEM_VMEMMAP
index ed173b8..efe2377 100644 (file)
@@ -947,24 +947,24 @@ long congestion_wait(int sync, long timeout)
 EXPORT_SYMBOL(congestion_wait);
 
 /**
- * wait_iff_congested - Conditionally wait for a backing_dev to become uncongested or a zone to complete writes
- * @zone: A zone to check if it is heavily congested
+ * wait_iff_congested - Conditionally wait for a backing_dev to become uncongested or a pgdat to complete writes
+ * @pgdat: A pgdat to check if it is heavily congested
  * @sync: SYNC or ASYNC IO
  * @timeout: timeout in jiffies
  *
  * In the event of a congested backing_dev (any backing_dev) and the given
- * @zone has experienced recent congestion, this waits for up to @timeout
+ * @pgdat has experienced recent congestion, this waits for up to @timeout
  * jiffies for either a BDI to exit congestion of the given @sync queue
  * or a write to complete.
  *
- * In the absence of zone congestion, cond_resched() is called to yield
+ * In the absence of pgdat congestion, cond_resched() is called to yield
  * the processor if necessary but otherwise does not sleep.
  *
  * The return value is 0 if the sleep is for the full timeout. Otherwise,
  * it is the number of jiffies that were still remaining when the function
  * returned. return_value == timeout implies the function did not sleep.
  */
-long wait_iff_congested(struct zone *zone, int sync, long timeout)
+long wait_iff_congested(struct pglist_data *pgdat, int sync, long timeout)
 {
        long ret;
        unsigned long start = jiffies;
@@ -973,12 +973,13 @@ long wait_iff_congested(struct zone *zone, int sync, long timeout)
 
        /*
         * If there is no congestion, or heavy congestion is not being
-        * encountered in the current zone, yield if necessary instead
+        * encountered in the current pgdat, yield if necessary instead
         * of sleeping on the congestion queue
         */
        if (atomic_read(&nr_wb_congested[sync]) == 0 ||
-           !test_bit(ZONE_CONGESTED, &zone->flags)) {
+           !test_bit(PGDAT_CONGESTED, &pgdat->flags)) {
                cond_resched();
+
                /* In case we scheduled, work out time remaining */
                ret = timeout - (jiffies - start);
                if (ret < 0)
index 64df5fe..9affb29 100644 (file)
@@ -331,7 +331,7 @@ static bool compact_trylock_irqsave(spinlock_t *lock, unsigned long *flags,
 {
        if (cc->mode == MIGRATE_ASYNC) {
                if (!spin_trylock_irqsave(lock, *flags)) {
-                       cc->contended = COMPACT_CONTENDED_LOCK;
+                       cc->contended = true;
                        return false;
                }
        } else {
@@ -365,13 +365,13 @@ static bool compact_unlock_should_abort(spinlock_t *lock,
        }
 
        if (fatal_signal_pending(current)) {
-               cc->contended = COMPACT_CONTENDED_SCHED;
+               cc->contended = true;
                return true;
        }
 
        if (need_resched()) {
                if (cc->mode == MIGRATE_ASYNC) {
-                       cc->contended = COMPACT_CONTENDED_SCHED;
+                       cc->contended = true;
                        return true;
                }
                cond_resched();
@@ -394,7 +394,7 @@ static inline bool compact_should_abort(struct compact_control *cc)
        /* async compaction aborts if contended */
        if (need_resched()) {
                if (cc->mode == MIGRATE_ASYNC) {
-                       cc->contended = COMPACT_CONTENDED_SCHED;
+                       cc->contended = true;
                        return true;
                }
 
@@ -646,8 +646,8 @@ static void acct_isolated(struct zone *zone, struct compact_control *cc)
        list_for_each_entry(page, &cc->migratepages, lru)
                count[!!page_is_file_cache(page)]++;
 
-       mod_zone_page_state(zone, NR_ISOLATED_ANON, count[0]);
-       mod_zone_page_state(zone, NR_ISOLATED_FILE, count[1]);
+       mod_node_page_state(zone->zone_pgdat, NR_ISOLATED_ANON, count[0]);
+       mod_node_page_state(zone->zone_pgdat, NR_ISOLATED_FILE, count[1]);
 }
 
 /* Similar to reclaim, but different enough that they don't share logic */
@@ -655,12 +655,12 @@ static bool too_many_isolated(struct zone *zone)
 {
        unsigned long active, inactive, isolated;
 
-       inactive = zone_page_state(zone, NR_INACTIVE_FILE) +
-                                       zone_page_state(zone, NR_INACTIVE_ANON);
-       active = zone_page_state(zone, NR_ACTIVE_FILE) +
-                                       zone_page_state(zone, NR_ACTIVE_ANON);
-       isolated = zone_page_state(zone, NR_ISOLATED_FILE) +
-                                       zone_page_state(zone, NR_ISOLATED_ANON);
+       inactive = node_page_state(zone->zone_pgdat, NR_INACTIVE_FILE) +
+                       node_page_state(zone->zone_pgdat, NR_INACTIVE_ANON);
+       active = node_page_state(zone->zone_pgdat, NR_ACTIVE_FILE) +
+                       node_page_state(zone->zone_pgdat, NR_ACTIVE_ANON);
+       isolated = node_page_state(zone->zone_pgdat, NR_ISOLATED_FILE) +
+                       node_page_state(zone->zone_pgdat, NR_ISOLATED_ANON);
 
        return isolated > (inactive + active) / 2;
 }
@@ -752,7 +752,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                 * if contended.
                 */
                if (!(low_pfn % SWAP_CLUSTER_MAX)
-                   && compact_unlock_should_abort(&zone->lru_lock, flags,
+                   && compact_unlock_should_abort(zone_lru_lock(zone), flags,
                                                                &locked, cc))
                        break;
 
@@ -813,7 +813,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                        if (unlikely(__PageMovable(page)) &&
                                        !PageIsolated(page)) {
                                if (locked) {
-                                       spin_unlock_irqrestore(&zone->lru_lock,
+                                       spin_unlock_irqrestore(zone_lru_lock(zone),
                                                                        flags);
                                        locked = false;
                                }
@@ -836,7 +836,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
 
                /* If we already hold the lock, we can skip some rechecking */
                if (!locked) {
-                       locked = compact_trylock_irqsave(&zone->lru_lock,
+                       locked = compact_trylock_irqsave(zone_lru_lock(zone),
                                                                &flags, cc);
                        if (!locked)
                                break;
@@ -856,7 +856,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                        }
                }
 
-               lruvec = mem_cgroup_page_lruvec(page, zone);
+               lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat);
 
                /* Try isolate the page */
                if (__isolate_lru_page(page, isolate_mode) != 0)
@@ -899,7 +899,7 @@ isolate_fail:
                 */
                if (nr_isolated) {
                        if (locked) {
-                               spin_unlock_irqrestore(&zone->lru_lock, flags);
+                               spin_unlock_irqrestore(zone_lru_lock(zone), flags);
                                locked = false;
                        }
                        acct_isolated(zone, cc);
@@ -927,7 +927,7 @@ isolate_fail:
                low_pfn = end_pfn;
 
        if (locked)
-               spin_unlock_irqrestore(&zone->lru_lock, flags);
+               spin_unlock_irqrestore(zone_lru_lock(zone), flags);
 
        /*
         * Update the pageblock-skip information and cached scanner pfn,
@@ -1200,7 +1200,7 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone,
        struct page *page;
        const isolate_mode_t isolate_mode =
                (sysctl_compact_unevictable_allowed ? ISOLATE_UNEVICTABLE : 0) |
-               (cc->mode == MIGRATE_ASYNC ? ISOLATE_ASYNC_MIGRATE : 0);
+               (cc->mode != MIGRATE_SYNC ? ISOLATE_ASYNC_MIGRATE : 0);
 
        /*
         * Start at where we last stopped, or beginning of the zone as
@@ -1619,14 +1619,11 @@ out:
        trace_mm_compaction_end(start_pfn, cc->migrate_pfn,
                                cc->free_pfn, end_pfn, sync, ret);
 
-       if (ret == COMPACT_CONTENDED)
-               ret = COMPACT_PARTIAL;
-
        return ret;
 }
 
 static enum compact_result compact_zone_order(struct zone *zone, int order,
-               gfp_t gfp_mask, enum migrate_mode mode, int *contended,
+               gfp_t gfp_mask, enum compact_priority prio,
                unsigned int alloc_flags, int classzone_idx)
 {
        enum compact_result ret;
@@ -1636,7 +1633,8 @@ static enum compact_result compact_zone_order(struct zone *zone, int order,
                .order = order,
                .gfp_mask = gfp_mask,
                .zone = zone,
-               .mode = mode,
+               .mode = (prio == COMPACT_PRIO_ASYNC) ?
+                                       MIGRATE_ASYNC : MIGRATE_SYNC_LIGHT,
                .alloc_flags = alloc_flags,
                .classzone_idx = classzone_idx,
                .direct_compaction = true,
@@ -1649,7 +1647,6 @@ static enum compact_result compact_zone_order(struct zone *zone, int order,
        VM_BUG_ON(!list_empty(&cc.freepages));
        VM_BUG_ON(!list_empty(&cc.migratepages));
 
-       *contended = cc.contended;
        return ret;
 }
 
@@ -1662,50 +1659,38 @@ int sysctl_extfrag_threshold = 500;
  * @alloc_flags: The allocation flags of the current allocation
  * @ac: The context of current allocation
  * @mode: The migration mode for async, sync light, or sync migration
- * @contended: Return value that determines if compaction was aborted due to
- *            need_resched() or lock contention
  *
  * This is the main entry point for direct page compaction.
  */
 enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order,
                unsigned int alloc_flags, const struct alloc_context *ac,
-               enum migrate_mode mode, int *contended)
+               enum compact_priority prio)
 {
        int may_enter_fs = gfp_mask & __GFP_FS;
        int may_perform_io = gfp_mask & __GFP_IO;
        struct zoneref *z;
        struct zone *zone;
        enum compact_result rc = COMPACT_SKIPPED;
-       int all_zones_contended = COMPACT_CONTENDED_LOCK; /* init for &= op */
-
-       *contended = COMPACT_CONTENDED_NONE;
 
        /* Check if the GFP flags allow compaction */
-       if (!order || !may_enter_fs || !may_perform_io)
+       if (!may_enter_fs || !may_perform_io)
                return COMPACT_SKIPPED;
 
-       trace_mm_compaction_try_to_compact_pages(order, gfp_mask, mode);
+       trace_mm_compaction_try_to_compact_pages(order, gfp_mask, prio);
 
        /* Compact each zone in the list */
        for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx,
                                                                ac->nodemask) {
                enum compact_result status;
-               int zone_contended;
 
                if (compaction_deferred(zone, order)) {
                        rc = max_t(enum compact_result, COMPACT_DEFERRED, rc);
                        continue;
                }
 
-               status = compact_zone_order(zone, order, gfp_mask, mode,
-                               &zone_contended, alloc_flags,
-                               ac_classzone_idx(ac));
+               status = compact_zone_order(zone, order, gfp_mask, prio,
+                                       alloc_flags, ac_classzone_idx(ac));
                rc = max(status, rc);
-               /*
-                * It takes at least one zone that wasn't lock contended
-                * to clear all_zones_contended.
-                */
-               all_zones_contended &= zone_contended;
 
                /* If a normal allocation would succeed, stop compacting */
                if (zone_watermark_ok(zone, order, low_wmark_pages(zone),
@@ -1717,59 +1702,29 @@ enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order,
                         * succeeds in this zone.
                         */
                        compaction_defer_reset(zone, order, false);
-                       /*
-                        * It is possible that async compaction aborted due to
-                        * need_resched() and the watermarks were ok thanks to
-                        * somebody else freeing memory. The allocation can
-                        * however still fail so we better signal the
-                        * need_resched() contention anyway (this will not
-                        * prevent the allocation attempt).
-                        */
-                       if (zone_contended == COMPACT_CONTENDED_SCHED)
-                               *contended = COMPACT_CONTENDED_SCHED;
 
-                       goto break_loop;
+                       break;
                }
 
-               if (mode != MIGRATE_ASYNC && (status == COMPACT_COMPLETE ||
-                                       status == COMPACT_PARTIAL_SKIPPED)) {
+               if (prio != COMPACT_PRIO_ASYNC && (status == COMPACT_COMPLETE ||
+                                       status == COMPACT_PARTIAL_SKIPPED))
                        /*
                         * We think that allocation won't succeed in this zone
                         * so we defer compaction there. If it ends up
                         * succeeding after all, it will be reset.
                         */
                        defer_compaction(zone, order);
-               }
 
                /*
                 * We might have stopped compacting due to need_resched() in
                 * async compaction, or due to a fatal signal detected. In that
-                * case do not try further zones and signal need_resched()
-                * contention.
-                */
-               if ((zone_contended == COMPACT_CONTENDED_SCHED)
-                                       || fatal_signal_pending(current)) {
-                       *contended = COMPACT_CONTENDED_SCHED;
-                       goto break_loop;
-               }
-
-               continue;
-break_loop:
-               /*
-                * We might not have tried all the zones, so  be conservative
-                * and assume they are not all lock contended.
+                * case do not try further zones
                 */
-               all_zones_contended = 0;
-               break;
+               if ((prio == COMPACT_PRIO_ASYNC && need_resched())
+                                       || fatal_signal_pending(current))
+                       break;
        }
 
-       /*
-        * If at least one zone wasn't deferred or skipped, we report if all
-        * zones that were tried were lock contended.
-        */
-       if (rc > COMPACT_INACTIVE && all_zones_contended)
-               *contended = COMPACT_CONTENDED_LOCK;
-
        return rc;
 }
 
index e90c154..c5f5e46 100644 (file)
@@ -95,8 +95,8 @@
  *    ->swap_lock              (try_to_unmap_one)
  *    ->private_lock           (try_to_unmap_one)
  *    ->tree_lock              (try_to_unmap_one)
- *    ->zone.lru_lock          (follow_page->mark_page_accessed)
- *    ->zone.lru_lock          (check_pte_range->isolate_lru_page)
+ *    ->zone_lru_lock(zone)    (follow_page->mark_page_accessed)
+ *    ->zone_lru_lock(zone)    (check_pte_range->isolate_lru_page)
  *    ->private_lock           (page_remove_rmap->set_page_dirty)
  *    ->tree_lock              (page_remove_rmap->set_page_dirty)
  *    bdi.wb->list_lock                (page_remove_rmap->set_page_dirty)
@@ -218,11 +218,11 @@ void __delete_from_page_cache(struct page *page, void *shadow)
 
        /* hugetlb pages do not participate in page cache accounting. */
        if (!PageHuge(page))
-               __mod_zone_page_state(page_zone(page), NR_FILE_PAGES, -nr);
+               __mod_node_page_state(page_pgdat(page), NR_FILE_PAGES, -nr);
        if (PageSwapBacked(page)) {
-               __mod_zone_page_state(page_zone(page), NR_SHMEM, -nr);
+               __mod_node_page_state(page_pgdat(page), NR_SHMEM, -nr);
                if (PageTransHuge(page))
-                       __dec_zone_page_state(page, NR_SHMEM_THPS);
+                       __dec_node_page_state(page, NR_SHMEM_THPS);
        } else {
                VM_BUG_ON_PAGE(PageTransHuge(page) && !PageHuge(page), page);
        }
@@ -568,9 +568,9 @@ int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask)
                 * hugetlb pages do not participate in page cache accounting.
                 */
                if (!PageHuge(new))
-                       __inc_zone_page_state(new, NR_FILE_PAGES);
+                       __inc_node_page_state(new, NR_FILE_PAGES);
                if (PageSwapBacked(new))
-                       __inc_zone_page_state(new, NR_SHMEM);
+                       __inc_node_page_state(new, NR_SHMEM);
                spin_unlock_irqrestore(&mapping->tree_lock, flags);
                mem_cgroup_migrate(old, new);
                radix_tree_preload_end();
@@ -677,7 +677,7 @@ static int __add_to_page_cache_locked(struct page *page,
 
        /* hugetlb pages do not participate in page cache accounting. */
        if (!huge)
-               __inc_zone_page_state(page, NR_FILE_PAGES);
+               __inc_node_page_state(page, NR_FILE_PAGES);
        spin_unlock_irq(&mapping->tree_lock);
        if (!huge)
                mem_cgroup_commit_charge(page, memcg, false, false);
index 3647334..2373f0a 100644 (file)
@@ -539,23 +539,26 @@ static int __do_huge_pmd_anonymous_page(struct fault_env *fe, struct page *page,
 }
 
 /*
- * If THP is set to always then directly reclaim/compact as necessary
- * If set to defer then do no reclaim and defer to khugepaged
+ * If THP defrag is set to always then directly reclaim/compact as necessary
+ * If set to defer then do only background reclaim/compact and defer to khugepaged
  * If set to madvise and the VMA is flagged then directly reclaim/compact
+ * When direct reclaim/compact is allowed, don't retry except for flagged VMA's
  */
 static inline gfp_t alloc_hugepage_direct_gfpmask(struct vm_area_struct *vma)
 {
-       gfp_t reclaim_flags = 0;
-
-       if (test_bit(TRANSPARENT_HUGEPAGE_DEFRAG_REQ_MADV_FLAG, &transparent_hugepage_flags) &&
-           (vma->vm_flags & VM_HUGEPAGE))
-               reclaim_flags = __GFP_DIRECT_RECLAIM;
-       else if (test_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG, &transparent_hugepage_flags))
-               reclaim_flags = __GFP_KSWAPD_RECLAIM;
-       else if (test_bit(TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG, &transparent_hugepage_flags))
-               reclaim_flags = __GFP_DIRECT_RECLAIM;
-
-       return GFP_TRANSHUGE | reclaim_flags;
+       bool vma_madvised = !!(vma->vm_flags & VM_HUGEPAGE);
+
+       if (test_bit(TRANSPARENT_HUGEPAGE_DEFRAG_REQ_MADV_FLAG,
+                               &transparent_hugepage_flags) && vma_madvised)
+               return GFP_TRANSHUGE;
+       else if (test_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG,
+                                               &transparent_hugepage_flags))
+               return GFP_TRANSHUGE_LIGHT | __GFP_KSWAPD_RECLAIM;
+       else if (test_bit(TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG,
+                                               &transparent_hugepage_flags))
+               return GFP_TRANSHUGE | (vma_madvised ? 0 : __GFP_NORETRY);
+
+       return GFP_TRANSHUGE_LIGHT;
 }
 
 /* Caller must hold page table lock. */
@@ -1249,25 +1252,26 @@ out:
        return 0;
 }
 
-int madvise_free_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
+/*
+ * Return true if we do MADV_FREE successfully on entire pmd page.
+ * Otherwise, return false.
+ */
+bool madvise_free_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
                pmd_t *pmd, unsigned long addr, unsigned long next)
-
 {
        spinlock_t *ptl;
        pmd_t orig_pmd;
        struct page *page;
        struct mm_struct *mm = tlb->mm;
-       int ret = 0;
+       bool ret = false;
 
        ptl = pmd_trans_huge_lock(pmd, vma);
        if (!ptl)
                goto out_unlocked;
 
        orig_pmd = *pmd;
-       if (is_huge_zero_pmd(orig_pmd)) {
-               ret = 1;
+       if (is_huge_zero_pmd(orig_pmd))
                goto out;
-       }
 
        page = pmd_page(orig_pmd);
        /*
@@ -1309,7 +1313,7 @@ int madvise_free_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
                set_pmd_at(mm, addr, pmd, orig_pmd);
                tlb_remove_pmd_tlb_entry(tlb, pmd, addr);
        }
-       ret = 1;
+       ret = true;
 out:
        spin_unlock(ptl);
 out_unlocked:
@@ -1586,7 +1590,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
 
        if (atomic_add_negative(-1, compound_mapcount_ptr(page))) {
                /* Last compound_mapcount is gone. */
-               __dec_zone_page_state(page, NR_ANON_THPS);
+               __dec_node_page_state(page, NR_ANON_THPS);
                if (TestClearPageDoubleMap(page)) {
                        /* No need in mapcount reference anymore */
                        for (i = 0; i < HPAGE_PMD_NR; i++)
@@ -1818,7 +1822,7 @@ static void __split_huge_page(struct page *page, struct list_head *list,
        pgoff_t end = -1;
        int i;
 
-       lruvec = mem_cgroup_page_lruvec(head, zone);
+       lruvec = mem_cgroup_page_lruvec(head, zone->zone_pgdat);
 
        /* complete memcg works before add pages to LRU */
        mem_cgroup_split_huge_fixup(head);
@@ -1848,7 +1852,7 @@ static void __split_huge_page(struct page *page, struct list_head *list,
                spin_unlock(&head->mapping->tree_lock);
        }
 
-       spin_unlock_irqrestore(&page_zone(head)->lru_lock, flags);
+       spin_unlock_irqrestore(zone_lru_lock(page_zone(head)), flags);
 
        unfreeze_page(head);
 
@@ -2034,7 +2038,7 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
                lru_add_drain();
 
        /* prevent PageLRU to go away from under us, and freeze lru stats */
-       spin_lock_irqsave(&page_zone(head)->lru_lock, flags);
+       spin_lock_irqsave(zone_lru_lock(page_zone(head)), flags);
 
        if (mapping) {
                void **pslot;
@@ -2061,7 +2065,7 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
                        list_del(page_deferred_list(head));
                }
                if (mapping)
-                       __dec_zone_page_state(page, NR_SHMEM_THPS);
+                       __dec_node_page_state(page, NR_SHMEM_THPS);
                spin_unlock(&pgdata->split_queue_lock);
                __split_huge_page(page, list, flags);
                ret = 0;
@@ -2077,7 +2081,7 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
                spin_unlock(&pgdata->split_queue_lock);
 fail:          if (mapping)
                        spin_unlock(&mapping->tree_lock);
-               spin_unlock_irqrestore(&page_zone(head)->lru_lock, flags);
+               spin_unlock_irqrestore(zone_lru_lock(page_zone(head)), flags);
                unfreeze_page(head);
                ret = -EBUSY;
        }
index abc1c5f..f904246 100644 (file)
@@ -3316,7 +3316,7 @@ static void unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
        address = address & huge_page_mask(h);
        pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) +
                        vma->vm_pgoff;
-       mapping = file_inode(vma->vm_file)->i_mapping;
+       mapping = vma->vm_file->f_mapping;
 
        /*
         * Take the mapping lock for the duration of the table walk. As
@@ -4391,7 +4391,6 @@ follow_huge_pud(struct mm_struct *mm, unsigned long address,
 
 /*
  * This function is called from memory failure code.
- * Assume the caller holds page lock of the head page.
  */
 int dequeue_hwpoisoned_huge_page(struct page *hpage)
 {
index 9b6a6c4..1501304 100644 (file)
@@ -78,7 +78,7 @@ extern unsigned long highest_memmap_pfn;
  */
 extern int isolate_lru_page(struct page *page);
 extern void putback_lru_page(struct page *page);
-extern bool zone_reclaimable(struct zone *zone);
+extern bool pgdat_reclaimable(struct pglist_data *pgdat);
 
 /*
  * in mm/rmap.c:
@@ -185,10 +185,7 @@ struct compact_control {
        const unsigned int alloc_flags; /* alloc flags of a direct compactor */
        const int classzone_idx;        /* zone index of a direct compactor */
        struct zone *zone;
-       int contended;                  /* Signal need_sched() or lock
-                                        * contention detected during
-                                        * compaction
-                                        */
+       bool contended;                 /* Signal lock or sched contention */
 };
 
 unsigned long
@@ -433,10 +430,10 @@ static inline void mminit_validate_memmodel_limits(unsigned long *start_pfn,
 }
 #endif /* CONFIG_SPARSEMEM */
 
-#define ZONE_RECLAIM_NOSCAN    -2
-#define ZONE_RECLAIM_FULL      -1
-#define ZONE_RECLAIM_SOME      0
-#define ZONE_RECLAIM_SUCCESS   1
+#define NODE_RECLAIM_NOSCAN    -2
+#define NODE_RECLAIM_FULL      -1
+#define NODE_RECLAIM_SOME      0
+#define NODE_RECLAIM_SUCCESS   1
 
 extern int hwpoison_filter(struct page *p);
 
@@ -467,7 +464,6 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone,
 #define ALLOC_HIGH             0x20 /* __GFP_HIGH set */
 #define ALLOC_CPUSET           0x40 /* check for correct cpuset */
 #define ALLOC_CMA              0x80 /* allow allocations from CMA areas */
-#define ALLOC_FAIR             0x100 /* fair zone allocation */
 
 enum ttu_flags;
 struct tlbflush_unmap_batch;
index 1548749..2976a9e 100644 (file)
@@ -7,5 +7,4 @@ CFLAGS_REMOVE_kasan.o = -pg
 # see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63533
 CFLAGS_kasan.o := $(call cc-option, -fno-conserve-stack -fno-stack-protector)
 
-obj-y := kasan.o report.o kasan_init.o
-obj-$(CONFIG_SLAB) += quarantine.o
+obj-y := kasan.o report.o kasan_init.o quarantine.o
index 6845f92..b6f99e8 100644 (file)
@@ -351,7 +351,6 @@ void kasan_free_pages(struct page *page, unsigned int order)
                                KASAN_FREE_PAGE);
 }
 
-#ifdef CONFIG_SLAB
 /*
  * Adaptive redzone policy taken from the userspace AddressSanitizer runtime.
  * For larger allocations larger redzones are used.
@@ -373,16 +372,8 @@ void kasan_cache_create(struct kmem_cache *cache, size_t *size,
                        unsigned long *flags)
 {
        int redzone_adjust;
-       /* Make sure the adjusted size is still less than
-        * KMALLOC_MAX_CACHE_SIZE.
-        * TODO: this check is only useful for SLAB, but not SLUB. We'll need
-        * to skip it for SLUB when it starts using kasan_cache_create().
-        */
-       if (*size > KMALLOC_MAX_CACHE_SIZE -
-           sizeof(struct kasan_alloc_meta) -
-           sizeof(struct kasan_free_meta))
-               return;
-       *flags |= SLAB_KASAN;
+       int orig_size = *size;
+
        /* Add alloc meta. */
        cache->kasan_info.alloc_meta_offset = *size;
        *size += sizeof(struct kasan_alloc_meta);
@@ -395,14 +386,26 @@ void kasan_cache_create(struct kmem_cache *cache, size_t *size,
        }
        redzone_adjust = optimal_redzone(cache->object_size) -
                (*size - cache->object_size);
+
        if (redzone_adjust > 0)
                *size += redzone_adjust;
-       *size = min(KMALLOC_MAX_CACHE_SIZE,
-                   max(*size,
-                       cache->object_size +
-                       optimal_redzone(cache->object_size)));
+
+       *size = min(KMALLOC_MAX_SIZE, max(*size, cache->object_size +
+                                       optimal_redzone(cache->object_size)));
+
+       /*
+        * If the metadata doesn't fit, don't enable KASAN at all.
+        */
+       if (*size <= cache->kasan_info.alloc_meta_offset ||
+                       *size <= cache->kasan_info.free_meta_offset) {
+               cache->kasan_info.alloc_meta_offset = 0;
+               cache->kasan_info.free_meta_offset = 0;
+               *size = orig_size;
+               return;
+       }
+
+       *flags |= SLAB_KASAN;
 }
-#endif
 
 void kasan_cache_shrink(struct kmem_cache *cache)
 {
@@ -414,6 +417,14 @@ void kasan_cache_destroy(struct kmem_cache *cache)
        quarantine_remove_cache(cache);
 }
 
+size_t kasan_metadata_size(struct kmem_cache *cache)
+{
+       return (cache->kasan_info.alloc_meta_offset ?
+               sizeof(struct kasan_alloc_meta) : 0) +
+               (cache->kasan_info.free_meta_offset ?
+               sizeof(struct kasan_free_meta) : 0);
+}
+
 void kasan_poison_slab(struct page *page)
 {
        kasan_poison_shadow(page_address(page),
@@ -431,16 +442,13 @@ void kasan_poison_object_data(struct kmem_cache *cache, void *object)
        kasan_poison_shadow(object,
                        round_up(cache->object_size, KASAN_SHADOW_SCALE_SIZE),
                        KASAN_KMALLOC_REDZONE);
-#ifdef CONFIG_SLAB
        if (cache->flags & SLAB_KASAN) {
                struct kasan_alloc_meta *alloc_info =
                        get_alloc_info(cache, object);
                alloc_info->state = KASAN_STATE_INIT;
        }
-#endif
 }
 
-#ifdef CONFIG_SLAB
 static inline int in_irqentry_text(unsigned long ptr)
 {
        return (ptr >= (unsigned long)&__irqentry_text_start &&
@@ -501,7 +509,6 @@ struct kasan_free_meta *get_free_info(struct kmem_cache *cache,
        BUILD_BUG_ON(sizeof(struct kasan_free_meta) > 32);
        return (void *)object + cache->kasan_info.free_meta_offset;
 }
-#endif
 
 void kasan_slab_alloc(struct kmem_cache *cache, void *object, gfp_t flags)
 {
@@ -522,16 +529,16 @@ static void kasan_poison_slab_free(struct kmem_cache *cache, void *object)
 
 bool kasan_slab_free(struct kmem_cache *cache, void *object)
 {
-#ifdef CONFIG_SLAB
        /* RCU slabs could be legally used after free within the RCU period */
        if (unlikely(cache->flags & SLAB_DESTROY_BY_RCU))
                return false;
 
        if (likely(cache->flags & SLAB_KASAN)) {
-               struct kasan_alloc_meta *alloc_info =
-                       get_alloc_info(cache, object);
-               struct kasan_free_meta *free_info =
-                       get_free_info(cache, object);
+               struct kasan_alloc_meta *alloc_info;
+               struct kasan_free_meta *free_info;
+
+               alloc_info = get_alloc_info(cache, object);
+               free_info = get_free_info(cache, object);
 
                switch (alloc_info->state) {
                case KASAN_STATE_ALLOC:
@@ -550,10 +557,6 @@ bool kasan_slab_free(struct kmem_cache *cache, void *object)
                }
        }
        return false;
-#else
-       kasan_poison_slab_free(cache, object);
-       return false;
-#endif
 }
 
 void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size,
@@ -576,7 +579,6 @@ void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size,
        kasan_unpoison_shadow(object, size);
        kasan_poison_shadow((void *)redzone_start, redzone_end - redzone_start,
                KASAN_KMALLOC_REDZONE);
-#ifdef CONFIG_SLAB
        if (cache->flags & SLAB_KASAN) {
                struct kasan_alloc_meta *alloc_info =
                        get_alloc_info(cache, object);
@@ -585,7 +587,6 @@ void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size,
                alloc_info->alloc_size = size;
                set_track(&alloc_info->track, flags);
        }
-#endif
 }
 EXPORT_SYMBOL(kasan_kmalloc);
 
index fb87923..31972cd 100644 (file)
@@ -95,7 +95,6 @@ struct kasan_alloc_meta *get_alloc_info(struct kmem_cache *cache,
 struct kasan_free_meta *get_free_info(struct kmem_cache *cache,
                                        const void *object);
 
-
 static inline const void *kasan_shadow_to_mem(const void *shadow_addr)
 {
        return (void *)(((unsigned long)shadow_addr - KASAN_SHADOW_OFFSET)
@@ -110,7 +109,7 @@ static inline bool kasan_report_enabled(void)
 void kasan_report(unsigned long addr, size_t size,
                bool is_write, unsigned long ip);
 
-#ifdef CONFIG_SLAB
+#if defined(CONFIG_SLAB) || defined(CONFIG_SLUB)
 void quarantine_put(struct kasan_free_meta *info, struct kmem_cache *cache);
 void quarantine_reduce(void);
 void quarantine_remove_cache(struct kmem_cache *cache);
index b3c122d..861b977 100644 (file)
@@ -116,7 +116,6 @@ static inline bool init_task_stack_addr(const void *addr)
                        sizeof(init_thread_union.stack));
 }
 
-#ifdef CONFIG_SLAB
 static void print_track(struct kasan_track *track)
 {
        pr_err("PID = %u\n", track->pid);
@@ -130,8 +129,8 @@ static void print_track(struct kasan_track *track)
        }
 }
 
-static void object_err(struct kmem_cache *cache, struct page *page,
-                       void *object, char *unused_reason)
+static void kasan_object_err(struct kmem_cache *cache, struct page *page,
+                               void *object, char *unused_reason)
 {
        struct kasan_alloc_meta *alloc_info = get_alloc_info(cache, object);
        struct kasan_free_meta *free_info;
@@ -162,7 +161,6 @@ static void object_err(struct kmem_cache *cache, struct page *page,
                break;
        }
 }
-#endif
 
 static void print_address_description(struct kasan_access_info *info)
 {
@@ -177,7 +175,7 @@ static void print_address_description(struct kasan_access_info *info)
                        struct kmem_cache *cache = page->slab_cache;
                        object = nearest_obj(cache, page,
                                                (void *)info->access_addr);
-                       object_err(cache, page, object,
+                       kasan_object_err(cache, page, object,
                                        "kasan: bad access detected");
                        return;
                }
index 7dbee69..79c52d0 100644 (file)
@@ -480,7 +480,7 @@ void __khugepaged_exit(struct mm_struct *mm)
 static void release_pte_page(struct page *page)
 {
        /* 0 stands for page_is_file_cache(page) == false */
-       dec_zone_page_state(page, NR_ISOLATED_ANON + 0);
+       dec_node_page_state(page, NR_ISOLATED_ANON + 0);
        unlock_page(page);
        putback_lru_page(page);
 }
@@ -576,7 +576,7 @@ static int __collapse_huge_page_isolate(struct vm_area_struct *vma,
                        goto out;
                }
                /* 0 stands for page_is_file_cache(page) == false */
-               inc_zone_page_state(page, NR_ISOLATED_ANON + 0);
+               inc_node_page_state(page, NR_ISOLATED_ANON + 0);
                VM_BUG_ON_PAGE(!PageLocked(page), page);
                VM_BUG_ON_PAGE(PageLRU(page), page);
 
@@ -672,10 +672,10 @@ static bool khugepaged_scan_abort(int nid)
        int i;
 
        /*
-        * If zone_reclaim_mode is disabled, then no extra effort is made to
+        * If node_reclaim_mode is disabled, then no extra effort is made to
         * allocate memory locally.
         */
-       if (!zone_reclaim_mode)
+       if (!node_reclaim_mode)
                return false;
 
        /* If there is a count for this node already, it must be acceptable */
@@ -694,7 +694,7 @@ static bool khugepaged_scan_abort(int nid)
 /* Defrag for khugepaged will enter direct reclaim/compaction if necessary */
 static inline gfp_t alloc_hugepage_khugepaged_gfpmask(void)
 {
-       return GFP_TRANSHUGE | (khugepaged_defrag() ? __GFP_DIRECT_RECLAIM : 0);
+       return khugepaged_defrag() ? GFP_TRANSHUGE : GFP_TRANSHUGE_LIGHT;
 }
 
 #ifdef CONFIG_NUMA
@@ -1483,10 +1483,10 @@ tree_unlocked:
                }
 
                local_irq_save(flags);
-               __inc_zone_page_state(new_page, NR_SHMEM_THPS);
+               __inc_node_page_state(new_page, NR_SHMEM_THPS);
                if (nr_none) {
-                       __mod_zone_page_state(zone, NR_FILE_PAGES, nr_none);
-                       __mod_zone_page_state(zone, NR_SHMEM, nr_none);
+                       __mod_node_page_state(zone->zone_pgdat, NR_FILE_PAGES, nr_none);
+                       __mod_node_page_state(zone->zone_pgdat, NR_SHMEM, nr_none);
                }
                local_irq_restore(flags);
 
index 04320d3..086292f 100644 (file)
@@ -1485,8 +1485,10 @@ static int kmemleak_scan_thread(void *arg)
         * Wait before the first scan to allow the system to fully initialize.
         */
        if (first_run) {
+               signed long timeout = msecs_to_jiffies(SECS_FIRST_SCAN * 1000);
                first_run = 0;
-               ssleep(SECS_FIRST_SCAN);
+               while (timeout && !kthread_should_stop())
+                       timeout = schedule_timeout_interruptible(timeout);
        }
 
        while (!kthread_should_stop()) {
index ca09915..ff5ff3b 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/seq_file.h>
 #include <linux/memblock.h>
 
-#include <asm-generic/sections.h>
+#include <asm/sections.h>
 #include <linux/io.h>
 
 #include "internal.h"
@@ -1027,7 +1027,7 @@ void __init_memblock __next_mem_range_rev(u64 *idx, int nid, ulong flags,
                                *out_end = m_end;
                        if (out_nid)
                                *out_nid = m_nid;
-                       idx_a++;
+                       idx_a--;
                        *idx = (u32)idx_a | (u64)idx_b << 32;
                        return;
                }
@@ -1465,15 +1465,16 @@ phys_addr_t __init_memblock memblock_end_of_DRAM(void)
        return (memblock.memory.regions[idx].base + memblock.memory.regions[idx].size);
 }
 
-void __init memblock_enforce_memory_limit(phys_addr_t limit)
+static phys_addr_t __init_memblock __find_max_addr(phys_addr_t limit)
 {
        phys_addr_t max_addr = (phys_addr_t)ULLONG_MAX;
        struct memblock_region *r;
 
-       if (!limit)
-               return;
-
-       /* find out max address */
+       /*
+        * translate the memory @limit size into the max address within one of
+        * the memory memblock regions, if the @limit exceeds the total size
+        * of those regions, max_addr will keep original value ULLONG_MAX
+        */
        for_each_memblock(memory, r) {
                if (limit <= r->size) {
                        max_addr = r->base + limit;
@@ -1482,6 +1483,22 @@ void __init memblock_enforce_memory_limit(phys_addr_t limit)
                limit -= r->size;
        }
 
+       return max_addr;
+}
+
+void __init memblock_enforce_memory_limit(phys_addr_t limit)
+{
+       phys_addr_t max_addr = (phys_addr_t)ULLONG_MAX;
+
+       if (!limit)
+               return;
+
+       max_addr = __find_max_addr(limit);
+
+       /* @limit exceeds the total size of the memory, do nothing */
+       if (max_addr == (phys_addr_t)ULLONG_MAX)
+               return;
+
        /* truncate both memory and reserved regions */
        memblock_remove_range(&memblock.memory, max_addr,
                              (phys_addr_t)ULLONG_MAX);
@@ -1489,6 +1506,36 @@ void __init memblock_enforce_memory_limit(phys_addr_t limit)
                              (phys_addr_t)ULLONG_MAX);
 }
 
+void __init memblock_mem_limit_remove_map(phys_addr_t limit)
+{
+       struct memblock_type *type = &memblock.memory;
+       phys_addr_t max_addr;
+       int i, ret, start_rgn, end_rgn;
+
+       if (!limit)
+               return;
+
+       max_addr = __find_max_addr(limit);
+
+       /* @limit exceeds the total size of the memory, do nothing */
+       if (max_addr == (phys_addr_t)ULLONG_MAX)
+               return;
+
+       ret = memblock_isolate_range(type, max_addr, (phys_addr_t)ULLONG_MAX,
+                               &start_rgn, &end_rgn);
+       if (ret)
+               return;
+
+       /* remove all the MAP regions above the limit */
+       for (i = end_rgn - 1; i >= start_rgn; i--) {
+               if (!memblock_is_nomap(&type->regions[i]))
+                       memblock_remove_region(type, i);
+       }
+       /* truncate the reserved regions */
+       memblock_remove_range(&memblock.reserved, max_addr,
+                             (phys_addr_t)ULLONG_MAX);
+}
+
 static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr)
 {
        unsigned int left = 0, right = type->cnt;
index f3a84c6..c265212 100644 (file)
@@ -132,15 +132,11 @@ static const char * const mem_cgroup_lru_names[] = {
  * their hierarchy representation
  */
 
-struct mem_cgroup_tree_per_zone {
+struct mem_cgroup_tree_per_node {
        struct rb_root rb_root;
        spinlock_t lock;
 };
 
-struct mem_cgroup_tree_per_node {
-       struct mem_cgroup_tree_per_zone rb_tree_per_zone[MAX_NR_ZONES];
-};
-
 struct mem_cgroup_tree {
        struct mem_cgroup_tree_per_node *rb_tree_per_node[MAX_NUMNODES];
 };
@@ -323,15 +319,6 @@ EXPORT_SYMBOL(memcg_kmem_enabled_key);
 
 #endif /* !CONFIG_SLOB */
 
-static struct mem_cgroup_per_zone *
-mem_cgroup_zone_zoneinfo(struct mem_cgroup *memcg, struct zone *zone)
-{
-       int nid = zone_to_nid(zone);
-       int zid = zone_idx(zone);
-
-       return &memcg->nodeinfo[nid]->zoneinfo[zid];
-}
-
 /**
  * mem_cgroup_css_from_page - css of the memcg associated with a page
  * @page: page of interest
@@ -383,37 +370,35 @@ ino_t page_cgroup_ino(struct page *page)
        return ino;
 }
 
-static struct mem_cgroup_per_zone *
-mem_cgroup_page_zoneinfo(struct mem_cgroup *memcg, struct page *page)
+static struct mem_cgroup_per_node *
+mem_cgroup_page_nodeinfo(struct mem_cgroup *memcg, struct page *page)
 {
        int nid = page_to_nid(page);
-       int zid = page_zonenum(page);
 
-       return &memcg->nodeinfo[nid]->zoneinfo[zid];
+       return memcg->nodeinfo[nid];
 }
 
-static struct mem_cgroup_tree_per_zone *
-soft_limit_tree_node_zone(int nid, int zid)
+static struct mem_cgroup_tree_per_node *
+soft_limit_tree_node(int nid)
 {
-       return &soft_limit_tree.rb_tree_per_node[nid]->rb_tree_per_zone[zid];
+       return soft_limit_tree.rb_tree_per_node[nid];
 }
 
-static struct mem_cgroup_tree_per_zone *
+static struct mem_cgroup_tree_per_node *
 soft_limit_tree_from_page(struct page *page)
 {
        int nid = page_to_nid(page);
-       int zid = page_zonenum(page);
 
-       return &soft_limit_tree.rb_tree_per_node[nid]->rb_tree_per_zone[zid];
+       return soft_limit_tree.rb_tree_per_node[nid];
 }
 
-static void __mem_cgroup_insert_exceeded(struct mem_cgroup_per_zone *mz,
-                                        struct mem_cgroup_tree_per_zone *mctz,
+static void __mem_cgroup_insert_exceeded(struct mem_cgroup_per_node *mz,
+                                        struct mem_cgroup_tree_per_node *mctz,
                                         unsigned long new_usage_in_excess)
 {
        struct rb_node **p = &mctz->rb_root.rb_node;
        struct rb_node *parent = NULL;
-       struct mem_cgroup_per_zone *mz_node;
+       struct mem_cgroup_per_node *mz_node;
 
        if (mz->on_tree)
                return;
@@ -423,7 +408,7 @@ static void __mem_cgroup_insert_exceeded(struct mem_cgroup_per_zone *mz,
                return;
        while (*p) {
                parent = *p;
-               mz_node = rb_entry(parent, struct mem_cgroup_per_zone,
+               mz_node = rb_entry(parent, struct mem_cgroup_per_node,
                                        tree_node);
                if (mz->usage_in_excess < mz_node->usage_in_excess)
                        p = &(*p)->rb_left;
@@ -439,8 +424,8 @@ static void __mem_cgroup_insert_exceeded(struct mem_cgroup_per_zone *mz,
        mz->on_tree = true;
 }
 
-static void __mem_cgroup_remove_exceeded(struct mem_cgroup_per_zone *mz,
-                                        struct mem_cgroup_tree_per_zone *mctz)
+static void __mem_cgroup_remove_exceeded(struct mem_cgroup_per_node *mz,
+                                        struct mem_cgroup_tree_per_node *mctz)
 {
        if (!mz->on_tree)
                return;
@@ -448,8 +433,8 @@ static void __mem_cgroup_remove_exceeded(struct mem_cgroup_per_zone *mz,
        mz->on_tree = false;
 }
 
-static void mem_cgroup_remove_exceeded(struct mem_cgroup_per_zone *mz,
-                                      struct mem_cgroup_tree_per_zone *mctz)
+static void mem_cgroup_remove_exceeded(struct mem_cgroup_per_node *mz,
+                                      struct mem_cgroup_tree_per_node *mctz)
 {
        unsigned long flags;
 
@@ -473,8 +458,8 @@ static unsigned long soft_limit_excess(struct mem_cgroup *memcg)
 static void mem_cgroup_update_tree(struct mem_cgroup *memcg, struct page *page)
 {
        unsigned long excess;
-       struct mem_cgroup_per_zone *mz;
-       struct mem_cgroup_tree_per_zone *mctz;
+       struct mem_cgroup_per_node *mz;
+       struct mem_cgroup_tree_per_node *mctz;
 
        mctz = soft_limit_tree_from_page(page);
        /*
@@ -482,7 +467,7 @@ static void mem_cgroup_update_tree(struct mem_cgroup *memcg, struct page *page)
         * because their event counter is not touched.
         */
        for (; memcg; memcg = parent_mem_cgroup(memcg)) {
-               mz = mem_cgroup_page_zoneinfo(memcg, page);
+               mz = mem_cgroup_page_nodeinfo(memcg, page);
                excess = soft_limit_excess(memcg);
                /*
                 * We have to update the tree if mz is on RB-tree or
@@ -507,24 +492,22 @@ static void mem_cgroup_update_tree(struct mem_cgroup *memcg, struct page *page)
 
 static void mem_cgroup_remove_from_trees(struct mem_cgroup *memcg)
 {
-       struct mem_cgroup_tree_per_zone *mctz;
-       struct mem_cgroup_per_zone *mz;
-       int nid, zid;
+       struct mem_cgroup_tree_per_node *mctz;
+       struct mem_cgroup_per_node *mz;
+       int nid;
 
        for_each_node(nid) {
-               for (zid = 0; zid < MAX_NR_ZONES; zid++) {
-                       mz = &memcg->nodeinfo[nid]->zoneinfo[zid];
-                       mctz = soft_limit_tree_node_zone(nid, zid);
-                       mem_cgroup_remove_exceeded(mz, mctz);
-               }
+               mz = mem_cgroup_nodeinfo(memcg, nid);
+               mctz = soft_limit_tree_node(nid);
+               mem_cgroup_remove_exceeded(mz, mctz);
        }
 }
 
-static struct mem_cgroup_per_zone *
-__mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_zone *mctz)
+static struct mem_cgroup_per_node *
+__mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_node *mctz)
 {
        struct rb_node *rightmost = NULL;
-       struct mem_cgroup_per_zone *mz;
+       struct mem_cgroup_per_node *mz;
 
 retry:
        mz = NULL;
@@ -532,7 +515,7 @@ retry:
        if (!rightmost)
                goto done;              /* Nothing to reclaim from */
 
-       mz = rb_entry(rightmost, struct mem_cgroup_per_zone, tree_node);
+       mz = rb_entry(rightmost, struct mem_cgroup_per_node, tree_node);
        /*
         * Remove the node now but someone else can add it back,
         * we will to add it back at the end of reclaim to its correct
@@ -546,10 +529,10 @@ done:
        return mz;
 }
 
-static struct mem_cgroup_per_zone *
-mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_zone *mctz)
+static struct mem_cgroup_per_node *
+mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_node *mctz)
 {
-       struct mem_cgroup_per_zone *mz;
+       struct mem_cgroup_per_node *mz;
 
        spin_lock_irq(&mctz->lock);
        mz = __mem_cgroup_largest_soft_limit_node(mctz);
@@ -643,20 +626,16 @@ unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
                                           int nid, unsigned int lru_mask)
 {
        unsigned long nr = 0;
-       int zid;
+       struct mem_cgroup_per_node *mz;
+       enum lru_list lru;
 
        VM_BUG_ON((unsigned)nid >= nr_node_ids);
 
-       for (zid = 0; zid < MAX_NR_ZONES; zid++) {
-               struct mem_cgroup_per_zone *mz;
-               enum lru_list lru;
-
-               for_each_lru(lru) {
-                       if (!(BIT(lru) & lru_mask))
-                               continue;
-                       mz = &memcg->nodeinfo[nid]->zoneinfo[zid];
-                       nr += mz->lru_size[lru];
-               }
+       for_each_lru(lru) {
+               if (!(BIT(lru) & lru_mask))
+                       continue;
+               mz = mem_cgroup_nodeinfo(memcg, nid);
+               nr += mz->lru_size[lru];
        }
        return nr;
 }
@@ -809,9 +788,9 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
        rcu_read_lock();
 
        if (reclaim) {
-               struct mem_cgroup_per_zone *mz;
+               struct mem_cgroup_per_node *mz;
 
-               mz = mem_cgroup_zone_zoneinfo(root, reclaim->zone);
+               mz = mem_cgroup_nodeinfo(root, reclaim->pgdat->node_id);
                iter = &mz->iter[reclaim->priority];
 
                if (prev && reclaim->generation != iter->generation)
@@ -910,19 +889,17 @@ static void invalidate_reclaim_iterators(struct mem_cgroup *dead_memcg)
 {
        struct mem_cgroup *memcg = dead_memcg;
        struct mem_cgroup_reclaim_iter *iter;
-       struct mem_cgroup_per_zone *mz;
-       int nid, zid;
+       struct mem_cgroup_per_node *mz;
+       int nid;
        int i;
 
        while ((memcg = parent_mem_cgroup(memcg))) {
                for_each_node(nid) {
-                       for (zid = 0; zid < MAX_NR_ZONES; zid++) {
-                               mz = &memcg->nodeinfo[nid]->zoneinfo[zid];
-                               for (i = 0; i <= DEF_PRIORITY; i++) {
-                                       iter = &mz->iter[i];
-                                       cmpxchg(&iter->position,
-                                               dead_memcg, NULL);
-                               }
+                       mz = mem_cgroup_nodeinfo(memcg, nid);
+                       for (i = 0; i <= DEF_PRIORITY; i++) {
+                               iter = &mz->iter[i];
+                               cmpxchg(&iter->position,
+                                       dead_memcg, NULL);
                        }
                }
        }
@@ -943,39 +920,6 @@ static void invalidate_reclaim_iterators(struct mem_cgroup *dead_memcg)
             iter != NULL;                              \
             iter = mem_cgroup_iter(NULL, iter, NULL))
 
-/**
- * mem_cgroup_zone_lruvec - get the lru list vector for a zone and memcg
- * @zone: zone of the wanted lruvec
- * @memcg: memcg of the wanted lruvec
- *
- * Returns the lru list vector holding pages for the given @zone and
- * @mem.  This can be the global zone lruvec, if the memory controller
- * is disabled.
- */
-struct lruvec *mem_cgroup_zone_lruvec(struct zone *zone,
-                                     struct mem_cgroup *memcg)
-{
-       struct mem_cgroup_per_zone *mz;
-       struct lruvec *lruvec;
-
-       if (mem_cgroup_disabled()) {
-               lruvec = &zone->lruvec;
-               goto out;
-       }
-
-       mz = mem_cgroup_zone_zoneinfo(memcg, zone);
-       lruvec = &mz->lruvec;
-out:
-       /*
-        * Since a node can be onlined after the mem_cgroup was created,
-        * we have to be prepared to initialize lruvec->zone here;
-        * and if offlined then reonlined, we need to reinitialize it.
-        */
-       if (unlikely(lruvec->zone != zone))
-               lruvec->zone = zone;
-       return lruvec;
-}
-
 /**
  * mem_cgroup_page_lruvec - return lruvec for isolating/putting an LRU page
  * @page: the page
@@ -985,14 +929,14 @@ out:
  * and putback protocol: the LRU lock must be held, and the page must
  * either be PageLRU() or the caller must have isolated/allocated it.
  */
-struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct zone *zone)
+struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct pglist_data *pgdat)
 {
-       struct mem_cgroup_per_zone *mz;
+       struct mem_cgroup_per_node *mz;
        struct mem_cgroup *memcg;
        struct lruvec *lruvec;
 
        if (mem_cgroup_disabled()) {
-               lruvec = &zone->lruvec;
+               lruvec = &pgdat->lruvec;
                goto out;
        }
 
@@ -1004,7 +948,7 @@ struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct zone *zone)
        if (!memcg)
                memcg = root_mem_cgroup;
 
-       mz = mem_cgroup_page_zoneinfo(memcg, page);
+       mz = mem_cgroup_page_nodeinfo(memcg, page);
        lruvec = &mz->lruvec;
 out:
        /*
@@ -1012,8 +956,8 @@ out:
         * we have to be prepared to initialize lruvec->zone here;
         * and if offlined then reonlined, we need to reinitialize it.
         */
-       if (unlikely(lruvec->zone != zone))
-               lruvec->zone = zone;
+       if (unlikely(lruvec->pgdat != pgdat))
+               lruvec->pgdat = pgdat;
        return lruvec;
 }
 
@@ -1030,17 +974,15 @@ out:
 void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru,
                                int nr_pages)
 {
-       struct mem_cgroup_per_zone *mz;
+       struct mem_cgroup_per_node *mz;
        unsigned long *lru_size;
        long size;
        bool empty;
 
-       __update_lru_size(lruvec, lru, nr_pages);
-
        if (mem_cgroup_disabled())
                return;
 
-       mz = container_of(lruvec, struct mem_cgroup_per_zone, lruvec);
+       mz = container_of(lruvec, struct mem_cgroup_per_node, lruvec);
        lru_size = mz->lru_size + lru;
        empty = list_empty(lruvec->lists + lru);
 
@@ -1276,9 +1218,9 @@ static bool mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask,
         * select it.  The goal is to allow it to allocate so that it may
         * quickly exit and free its memory.
         */
-       if (fatal_signal_pending(current) || task_will_free_mem(current)) {
+       if (task_will_free_mem(current)) {
                mark_oom_victim(current);
-               try_oom_reaper(current);
+               wake_oom_reaper(current);
                goto unlock;
        }
 
@@ -1433,7 +1375,7 @@ int mem_cgroup_select_victim_node(struct mem_cgroup *memcg)
 #endif
 
 static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg,
-                                  struct zone *zone,
+                                  pg_data_t *pgdat,
                                   gfp_t gfp_mask,
                                   unsigned long *total_scanned)
 {
@@ -1443,7 +1385,7 @@ static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg,
        unsigned long excess;
        unsigned long nr_scanned;
        struct mem_cgroup_reclaim_cookie reclaim = {
-               .zone = zone,
+               .pgdat = pgdat,
                .priority = 0,
        };
 
@@ -1473,8 +1415,8 @@ static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg,
                        }
                        continue;
                }
-               total += mem_cgroup_shrink_node_zone(victim, gfp_mask, false,
-                                                    zone, &nr_scanned);
+               total += mem_cgroup_shrink_node(victim, gfp_mask, false,
+                                       pgdat, &nr_scanned);
                *total_scanned += nr_scanned;
                if (!soft_limit_excess(root_memcg))
                        break;
@@ -2107,11 +2049,11 @@ static void lock_page_lru(struct page *page, int *isolated)
 {
        struct zone *zone = page_zone(page);
 
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irq(zone_lru_lock(zone));
        if (PageLRU(page)) {
                struct lruvec *lruvec;
 
-               lruvec = mem_cgroup_page_lruvec(page, zone);
+               lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat);
                ClearPageLRU(page);
                del_page_from_lru_list(page, lruvec, page_lru(page));
                *isolated = 1;
@@ -2126,12 +2068,12 @@ static void unlock_page_lru(struct page *page, int isolated)
        if (isolated) {
                struct lruvec *lruvec;
 
-               lruvec = mem_cgroup_page_lruvec(page, zone);
+               lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat);
                VM_BUG_ON_PAGE(PageLRU(page), page);
                SetPageLRU(page);
                add_page_to_lru_list(page, lruvec, page_lru(page));
        }
-       spin_unlock_irq(&zone->lru_lock);
+       spin_unlock_irq(zone_lru_lock(zone));
 }
 
 static void commit_charge(struct page *page, struct mem_cgroup *memcg,
@@ -2431,7 +2373,7 @@ void memcg_kmem_uncharge(struct page *page, int order)
 
 /*
  * Because tail pages are not marked as "used", set it. We're under
- * zone->lru_lock and migration entries setup in all page mappings.
+ * zone_lru_lock and migration entries setup in all page mappings.
  */
 void mem_cgroup_split_huge_fixup(struct page *head)
 {
@@ -2601,22 +2543,22 @@ static int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
        return ret;
 }
 
-unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
+unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,
                                            gfp_t gfp_mask,
                                            unsigned long *total_scanned)
 {
        unsigned long nr_reclaimed = 0;
-       struct mem_cgroup_per_zone *mz, *next_mz = NULL;
+       struct mem_cgroup_per_node *mz, *next_mz = NULL;
        unsigned long reclaimed;
        int loop = 0;
-       struct mem_cgroup_tree_per_zone *mctz;
+       struct mem_cgroup_tree_per_node *mctz;
        unsigned long excess;
        unsigned long nr_scanned;
 
        if (order > 0)
                return 0;
 
-       mctz = soft_limit_tree_node_zone(zone_to_nid(zone), zone_idx(zone));
+       mctz = soft_limit_tree_node(pgdat->node_id);
        /*
         * This loop can run a while, specially if mem_cgroup's continuously
         * keep exceeding their soft limit and putting the system under
@@ -2631,7 +2573,7 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
                        break;
 
                nr_scanned = 0;
-               reclaimed = mem_cgroup_soft_reclaim(mz->memcg, zone,
+               reclaimed = mem_cgroup_soft_reclaim(mz->memcg, pgdat,
                                                    gfp_mask, &nr_scanned);
                nr_reclaimed += reclaimed;
                *total_scanned += nr_scanned;
@@ -3252,22 +3194,21 @@ static int memcg_stat_show(struct seq_file *m, void *v)
 
 #ifdef CONFIG_DEBUG_VM
        {
-               int nid, zid;
-               struct mem_cgroup_per_zone *mz;
+               pg_data_t *pgdat;
+               struct mem_cgroup_per_node *mz;
                struct zone_reclaim_stat *rstat;
                unsigned long recent_rotated[2] = {0, 0};
                unsigned long recent_scanned[2] = {0, 0};
 
-               for_each_online_node(nid)
-                       for (zid = 0; zid < MAX_NR_ZONES; zid++) {
-                               mz = &memcg->nodeinfo[nid]->zoneinfo[zid];
-                               rstat = &mz->lruvec.reclaim_stat;
+               for_each_online_pgdat(pgdat) {
+                       mz = mem_cgroup_nodeinfo(memcg, pgdat->node_id);
+                       rstat = &mz->lruvec.reclaim_stat;
 
-                               recent_rotated[0] += rstat->recent_rotated[0];
-                               recent_rotated[1] += rstat->recent_rotated[1];
-                               recent_scanned[0] += rstat->recent_scanned[0];
-                               recent_scanned[1] += rstat->recent_scanned[1];
-                       }
+                       recent_rotated[0] += rstat->recent_rotated[0];
+                       recent_rotated[1] += rstat->recent_rotated[1];
+                       recent_scanned[0] += rstat->recent_scanned[0];
+                       recent_scanned[1] += rstat->recent_scanned[1];
+               }
                seq_printf(m, "recent_rotated_anon %lu\n", recent_rotated[0]);
                seq_printf(m, "recent_rotated_file %lu\n", recent_rotated[1]);
                seq_printf(m, "recent_scanned_anon %lu\n", recent_scanned[0]);
@@ -4147,11 +4088,10 @@ struct mem_cgroup *mem_cgroup_from_id(unsigned short id)
        return idr_find(&mem_cgroup_idr, id);
 }
 
-static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node)
+static int alloc_mem_cgroup_per_node_info(struct mem_cgroup *memcg, int node)
 {
        struct mem_cgroup_per_node *pn;
-       struct mem_cgroup_per_zone *mz;
-       int zone, tmp = node;
+       int tmp = node;
        /*
         * This routine is called against possible nodes.
         * But it's BUG to call kmalloc() against offline node.
@@ -4166,18 +4106,16 @@ static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node)
        if (!pn)
                return 1;
 
-       for (zone = 0; zone < MAX_NR_ZONES; zone++) {
-               mz = &pn->zoneinfo[zone];
-               lruvec_init(&mz->lruvec);
-               mz->usage_in_excess = 0;
-               mz->on_tree = false;
-               mz->memcg = memcg;
-       }
+       lruvec_init(&pn->lruvec);
+       pn->usage_in_excess = 0;
+       pn->on_tree = false;
+       pn->memcg = memcg;
+
        memcg->nodeinfo[node] = pn;
        return 0;
 }
 
-static void free_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node)
+static void free_mem_cgroup_per_node_info(struct mem_cgroup *memcg, int node)
 {
        kfree(memcg->nodeinfo[node]);
 }
@@ -4188,7 +4126,7 @@ static void mem_cgroup_free(struct mem_cgroup *memcg)
 
        memcg_wb_domain_exit(memcg);
        for_each_node(node)
-               free_mem_cgroup_per_zone_info(memcg, node);
+               free_mem_cgroup_per_node_info(memcg, node);
        free_percpu(memcg->stat);
        kfree(memcg);
 }
@@ -4217,7 +4155,7 @@ static struct mem_cgroup *mem_cgroup_alloc(void)
                goto fail;
 
        for_each_node(node)
-               if (alloc_mem_cgroup_per_zone_info(memcg, node))
+               if (alloc_mem_cgroup_per_node_info(memcg, node))
                        goto fail;
 
        if (memcg_wb_domain_init(memcg, GFP_KERNEL))
@@ -5233,7 +5171,7 @@ static int memory_stat_show(struct seq_file *m, void *v)
        seq_printf(m, "file %llu\n",
                   (u64)stat[MEM_CGROUP_STAT_CACHE] * PAGE_SIZE);
        seq_printf(m, "kernel_stack %llu\n",
-                  (u64)stat[MEMCG_KERNEL_STACK] * PAGE_SIZE);
+                  (u64)stat[MEMCG_KERNEL_STACK_KB] * 1024);
        seq_printf(m, "slab %llu\n",
                   (u64)(stat[MEMCG_SLAB_RECLAIMABLE] +
                         stat[MEMCG_SLAB_UNRECLAIMABLE]) * PAGE_SIZE);
@@ -5820,18 +5758,12 @@ static int __init mem_cgroup_init(void)
 
        for_each_node(node) {
                struct mem_cgroup_tree_per_node *rtpn;
-               int zone;
 
                rtpn = kzalloc_node(sizeof(*rtpn), GFP_KERNEL,
                                    node_online(node) ? node : NUMA_NO_NODE);
 
-               for (zone = 0; zone < MAX_NR_ZONES; zone++) {
-                       struct mem_cgroup_tree_per_zone *rtpz;
-
-                       rtpz = &rtpn->rb_tree_per_zone[zone];
-                       rtpz->rb_root = RB_ROOT;
-                       spin_lock_init(&rtpz->lock);
-               }
+               rtpn->rb_root = RB_ROOT;
+               spin_lock_init(&rtpn->lock);
                soft_limit_tree.rb_tree_per_node[node] = rtpn;
        }
 
index 2fcca6b..de88f33 100644 (file)
@@ -741,8 +741,6 @@ static int me_huge_page(struct page *p, unsigned long pfn)
         * page->lru because it can be used in other hugepage operations,
         * such as __unmap_hugepage_range() and gather_surplus_pages().
         * So instead we use page_mapping() and PageAnon().
-        * We assume that this function is called with page lock held,
-        * so there is no race between isolation and mapping/unmapping.
         */
        if (!(page_mapping(hpage) || PageAnon(hpage))) {
                res = dequeue_hwpoisoned_huge_page(hpage);
@@ -1663,7 +1661,7 @@ static int __soft_offline_page(struct page *page, int flags)
        put_hwpoison_page(page);
        if (!ret) {
                LIST_HEAD(pagelist);
-               inc_zone_page_state(page, NR_ISOLATED_ANON +
+               inc_node_page_state(page, NR_ISOLATED_ANON +
                                        page_is_file_cache(page));
                list_add(&page->lru, &pagelist);
                ret = migrate_pages(&pagelist, new_page, NULL, MPOL_MF_MOVE_ALL,
@@ -1671,7 +1669,7 @@ static int __soft_offline_page(struct page *page, int flags)
                if (ret) {
                        if (!list_empty(&pagelist)) {
                                list_del(&page->lru);
-                               dec_zone_page_state(page, NR_ISOLATED_ANON +
+                               dec_node_page_state(page, NR_ISOLATED_ANON +
                                                page_is_file_cache(page));
                                putback_lru_page(page);
                        }
index 82d0b98..3894b65 100644 (file)
@@ -1209,9 +1209,10 @@ static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start)
 
                arch_refresh_nodedata(nid, pgdat);
        } else {
-               /* Reset the nr_zones and classzone_idx to 0 before reuse */
+               /* Reset the nr_zones, order and classzone_idx before reuse */
                pgdat->nr_zones = 0;
-               pgdat->classzone_idx = 0;
+               pgdat->kswapd_order = 0;
+               pgdat->kswapd_classzone_idx = 0;
        }
 
        /* we can use NODE_DATA(nid) from here */
@@ -1547,6 +1548,37 @@ static unsigned long scan_movable_pages(unsigned long start, unsigned long end)
        return 0;
 }
 
+static struct page *new_node_page(struct page *page, unsigned long private,
+               int **result)
+{
+       gfp_t gfp_mask = GFP_USER | __GFP_MOVABLE;
+       int nid = page_to_nid(page);
+       nodemask_t nmask = node_online_map;
+       struct page *new_page;
+
+       /*
+        * TODO: allocate a destination hugepage from a nearest neighbor node,
+        * accordance with memory policy of the user process if possible. For
+        * now as a simple work-around, we use the next node for destination.
+        */
+       if (PageHuge(page))
+               return alloc_huge_page_node(page_hstate(compound_head(page)),
+                                       next_node_in(nid, nmask));
+
+       node_clear(nid, nmask);
+       if (PageHighMem(page)
+           || (zone_idx(page_zone(page)) == ZONE_MOVABLE))
+               gfp_mask |= __GFP_HIGHMEM;
+
+       new_page = __alloc_pages_nodemask(gfp_mask, 0,
+                                       node_zonelist(nid, gfp_mask), &nmask);
+       if (!new_page)
+               new_page = __alloc_pages(gfp_mask, 0,
+                                       node_zonelist(nid, gfp_mask));
+
+       return new_page;
+}
+
 #define NR_OFFLINE_AT_ONCE_PAGES       (256)
 static int
 do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
@@ -1586,7 +1618,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                        put_page(page);
                        list_add_tail(&page->lru, &source);
                        move_pages--;
-                       inc_zone_page_state(page, NR_ISOLATED_ANON +
+                       inc_node_page_state(page, NR_ISOLATED_ANON +
                                            page_is_file_cache(page));
 
                } else {
@@ -1610,11 +1642,8 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                        goto out;
                }
 
-               /*
-                * alloc_migrate_target should be improooooved!!
-                * migrate_pages returns # of failed pages.
-                */
-               ret = migrate_pages(&source, alloc_migrate_target, NULL, 0,
+               /* Allocate a new page from the nearest neighbor node */
+               ret = migrate_pages(&source, new_node_page, NULL, 0,
                                        MIGRATE_SYNC, MR_MEMORY_HOTPLUG);
                if (ret)
                        putback_movable_pages(&source);
index 53e40d3..d8c4e38 100644 (file)
@@ -962,7 +962,7 @@ static void migrate_page_add(struct page *page, struct list_head *pagelist,
        if ((flags & MPOL_MF_MOVE_ALL) || page_mapcount(page) == 1) {
                if (!isolate_lru_page(page)) {
                        list_add_tail(&page->lru, pagelist);
-                       inc_zone_page_state(page, NR_ISOLATED_ANON +
+                       inc_node_page_state(page, NR_ISOLATED_ANON +
                                            page_is_file_cache(page));
                }
        }
index 8f65464..47a659d 100644 (file)
@@ -306,7 +306,7 @@ EXPORT_SYMBOL(mempool_resize);
  * returns NULL. Note that due to preallocation, this function
  * *never* fails when called from process contexts. (it might
  * fail if called from an IRQ context.)
- * Note: neither __GFP_NOMEMALLOC nor __GFP_ZERO are supported.
+ * Note: using __GFP_ZERO is not supported.
  */
 void *mempool_alloc(mempool_t *pool, gfp_t gfp_mask)
 {
@@ -315,27 +315,16 @@ void *mempool_alloc(mempool_t *pool, gfp_t gfp_mask)
        wait_queue_t wait;
        gfp_t gfp_temp;
 
-       /* If oom killed, memory reserves are essential to prevent livelock */
-       VM_WARN_ON_ONCE(gfp_mask & __GFP_NOMEMALLOC);
-       /* No element size to zero on allocation */
        VM_WARN_ON_ONCE(gfp_mask & __GFP_ZERO);
-
        might_sleep_if(gfp_mask & __GFP_DIRECT_RECLAIM);
 
+       gfp_mask |= __GFP_NOMEMALLOC;   /* don't allocate emergency reserves */
        gfp_mask |= __GFP_NORETRY;      /* don't loop in __alloc_pages */
        gfp_mask |= __GFP_NOWARN;       /* failures are OK */
 
        gfp_temp = gfp_mask & ~(__GFP_DIRECT_RECLAIM|__GFP_IO);
 
 repeat_alloc:
-       if (likely(pool->curr_nr)) {
-               /*
-                * Don't allocate from emergency reserves if there are
-                * elements available.  This check is racy, but it will
-                * be rechecked each loop.
-                */
-               gfp_temp |= __GFP_NOMEMALLOC;
-       }
 
        element = pool->alloc(gfp_temp, pool->pool_data);
        if (likely(element != NULL))
@@ -359,12 +348,11 @@ repeat_alloc:
         * We use gfp mask w/o direct reclaim or IO for the first round.  If
         * alloc failed with that and @pool was empty, retry immediately.
         */
-       if ((gfp_temp & ~__GFP_NOMEMALLOC) != gfp_mask) {
+       if (gfp_temp != gfp_mask) {
                spin_unlock_irqrestore(&pool->lock, flags);
                gfp_temp = gfp_mask;
                goto repeat_alloc;
        }
-       gfp_temp = gfp_mask;
 
        /* We must not sleep if !__GFP_DIRECT_RECLAIM */
        if (!(gfp_mask & __GFP_DIRECT_RECLAIM)) {
index 2232f69..f7ee04a 100644 (file)
@@ -168,7 +168,7 @@ void putback_movable_pages(struct list_head *l)
                        continue;
                }
                list_del(&page->lru);
-               dec_zone_page_state(page, NR_ISOLATED_ANON +
+               dec_node_page_state(page, NR_ISOLATED_ANON +
                                page_is_file_cache(page));
                /*
                 * We isolated non-lru movable page so here we can use
@@ -501,19 +501,21 @@ int migrate_page_move_mapping(struct address_space *mapping,
         * new page and drop references to the old page.
         *
         * Note that anonymous pages are accounted for
-        * via NR_FILE_PAGES and NR_ANON_PAGES if they
+        * via NR_FILE_PAGES and NR_ANON_MAPPED if they
         * are mapped to swap space.
         */
        if (newzone != oldzone) {
-               __dec_zone_state(oldzone, NR_FILE_PAGES);
-               __inc_zone_state(newzone, NR_FILE_PAGES);
+               __dec_node_state(oldzone->zone_pgdat, NR_FILE_PAGES);
+               __inc_node_state(newzone->zone_pgdat, NR_FILE_PAGES);
                if (PageSwapBacked(page) && !PageSwapCache(page)) {
-                       __dec_zone_state(oldzone, NR_SHMEM);
-                       __inc_zone_state(newzone, NR_SHMEM);
+                       __dec_node_state(oldzone->zone_pgdat, NR_SHMEM);
+                       __inc_node_state(newzone->zone_pgdat, NR_SHMEM);
                }
                if (dirty && mapping_cap_account_dirty(mapping)) {
-                       __dec_zone_state(oldzone, NR_FILE_DIRTY);
-                       __inc_zone_state(newzone, NR_FILE_DIRTY);
+                       __dec_node_state(oldzone->zone_pgdat, NR_FILE_DIRTY);
+                       __dec_zone_state(oldzone, NR_ZONE_WRITE_PENDING);
+                       __inc_node_state(newzone->zone_pgdat, NR_FILE_DIRTY);
+                       __inc_zone_state(newzone, NR_ZONE_WRITE_PENDING);
                }
        }
        local_irq_enable();
@@ -1119,7 +1121,7 @@ out:
                 * restored.
                 */
                list_del(&page->lru);
-               dec_zone_page_state(page, NR_ISOLATED_ANON +
+               dec_node_page_state(page, NR_ISOLATED_ANON +
                                page_is_file_cache(page));
        }
 
@@ -1460,7 +1462,7 @@ static int do_move_page_to_node_array(struct mm_struct *mm,
                err = isolate_lru_page(page);
                if (!err) {
                        list_add_tail(&page->lru, &pagelist);
-                       inc_zone_page_state(page, NR_ISOLATED_ANON +
+                       inc_node_page_state(page, NR_ISOLATED_ANON +
                                            page_is_file_cache(page));
                }
 put_and_set:
@@ -1726,15 +1728,16 @@ static bool migrate_balanced_pgdat(struct pglist_data *pgdat,
                                   unsigned long nr_migrate_pages)
 {
        int z;
+
+       if (!pgdat_reclaimable(pgdat))
+               return false;
+
        for (z = pgdat->nr_zones - 1; z >= 0; z--) {
                struct zone *zone = pgdat->node_zones + z;
 
                if (!populated_zone(zone))
                        continue;
 
-               if (!zone_reclaimable(zone))
-                       continue;
-
                /* Avoid waking kswapd by allocating pages_to_migrate pages. */
                if (!zone_watermark_ok(zone, 0,
                                       high_wmark_pages(zone) +
@@ -1828,7 +1831,7 @@ static int numamigrate_isolate_page(pg_data_t *pgdat, struct page *page)
        }
 
        page_lru = page_is_file_cache(page);
-       mod_zone_page_state(page_zone(page), NR_ISOLATED_ANON + page_lru,
+       mod_node_page_state(page_pgdat(page), NR_ISOLATED_ANON + page_lru,
                                hpage_nr_pages(page));
 
        /*
@@ -1886,7 +1889,7 @@ int migrate_misplaced_page(struct page *page, struct vm_area_struct *vma,
        if (nr_remaining) {
                if (!list_empty(&migratepages)) {
                        list_del(&page->lru);
-                       dec_zone_page_state(page, NR_ISOLATED_ANON +
+                       dec_node_page_state(page, NR_ISOLATED_ANON +
                                        page_is_file_cache(page));
                        putback_lru_page(page);
                }
@@ -1931,7 +1934,7 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,
                goto out_dropref;
 
        new_page = alloc_pages_node(node,
-               (GFP_TRANSHUGE | __GFP_THISNODE) & ~__GFP_RECLAIM,
+               (GFP_TRANSHUGE_LIGHT | __GFP_THISNODE),
                HPAGE_PMD_ORDER);
        if (!new_page)
                goto out_fail;
@@ -1979,7 +1982,7 @@ fail_putback:
                /* Retake the callers reference and putback on LRU */
                get_page(page);
                putback_lru_page(page);
-               mod_zone_page_state(page_zone(page),
+               mod_node_page_state(page_pgdat(page),
                         NR_ISOLATED_ANON + page_lru, -HPAGE_PMD_NR);
 
                goto out_unlock;
@@ -2030,7 +2033,7 @@ fail_putback:
        count_vm_events(PGMIGRATE_SUCCESS, HPAGE_PMD_NR);
        count_vm_numa_events(NUMA_PAGE_MIGRATE, HPAGE_PMD_NR);
 
-       mod_zone_page_state(page_zone(page),
+       mod_node_page_state(page_pgdat(page),
                        NR_ISOLATED_ANON + page_lru,
                        -HPAGE_PMD_NR);
        return isolated;
index ef8dc9f..14645be 100644 (file)
@@ -103,7 +103,7 @@ static bool __munlock_isolate_lru_page(struct page *page, bool getpage)
        if (PageLRU(page)) {
                struct lruvec *lruvec;
 
-               lruvec = mem_cgroup_page_lruvec(page, page_zone(page));
+               lruvec = mem_cgroup_page_lruvec(page, page_pgdat(page));
                if (getpage)
                        get_page(page);
                ClearPageLRU(page);
@@ -188,7 +188,7 @@ unsigned int munlock_vma_page(struct page *page)
         * might otherwise copy PageMlocked to part of the tail pages before
         * we clear it in the head page. It also stabilizes hpage_nr_pages().
         */
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irq(zone_lru_lock(zone));
 
        nr_pages = hpage_nr_pages(page);
        if (!TestClearPageMlocked(page))
@@ -197,14 +197,14 @@ unsigned int munlock_vma_page(struct page *page)
        __mod_zone_page_state(zone, NR_MLOCK, -nr_pages);
 
        if (__munlock_isolate_lru_page(page, true)) {
-               spin_unlock_irq(&zone->lru_lock);
+               spin_unlock_irq(zone_lru_lock(zone));
                __munlock_isolated_page(page);
                goto out;
        }
        __munlock_isolation_failed(page);
 
 unlock_out:
-       spin_unlock_irq(&zone->lru_lock);
+       spin_unlock_irq(zone_lru_lock(zone));
 
 out:
        return nr_pages - 1;
@@ -289,7 +289,7 @@ static void __munlock_pagevec(struct pagevec *pvec, struct zone *zone)
        pagevec_init(&pvec_putback, 0);
 
        /* Phase 1: page isolation */
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irq(zone_lru_lock(zone));
        for (i = 0; i < nr; i++) {
                struct page *page = pvec->pages[i];
 
@@ -315,7 +315,7 @@ static void __munlock_pagevec(struct pagevec *pvec, struct zone *zone)
        }
        delta_munlocked = -nr + pagevec_count(&pvec_putback);
        __mod_zone_page_state(zone, NR_MLOCK, delta_munlocked);
-       spin_unlock_irq(&zone->lru_lock);
+       spin_unlock_irq(zone_lru_lock(zone));
 
        /* Now we can release pins of pages that we are not munlocking */
        pagevec_release(&pvec_putback);
index 86b18f3..d44bee9 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -621,7 +621,6 @@ int vma_adjust(struct vm_area_struct *vma, unsigned long start,
 {
        struct mm_struct *mm = vma->vm_mm;
        struct vm_area_struct *next = vma->vm_next;
-       struct vm_area_struct *importer = NULL;
        struct address_space *mapping = NULL;
        struct rb_root *root = NULL;
        struct anon_vma *anon_vma = NULL;
@@ -631,17 +630,25 @@ int vma_adjust(struct vm_area_struct *vma, unsigned long start,
        int remove_next = 0;
 
        if (next && !insert) {
-               struct vm_area_struct *exporter = NULL;
+               struct vm_area_struct *exporter = NULL, *importer = NULL;
 
                if (end >= next->vm_end) {
                        /*
                         * vma expands, overlapping all the next, and
                         * perhaps the one after too (mprotect case 6).
                         */
-again:                 remove_next = 1 + (end > next->vm_end);
+                       remove_next = 1 + (end > next->vm_end);
                        end = next->vm_end;
                        exporter = next;
                        importer = vma;
+
+                       /*
+                        * If next doesn't have anon_vma, import from vma after
+                        * next, if the vma overlaps with it.
+                        */
+                       if (remove_next == 2 && next && !next->anon_vma)
+                               exporter = next->vm_next;
+
                } else if (end > next->vm_start) {
                        /*
                         * vma expands, overlapping part of the next:
@@ -675,7 +682,7 @@ again:                      remove_next = 1 + (end > next->vm_end);
                                return error;
                }
        }
-
+again:
        vma_adjust_trans_huge(vma, start, end, adjust_next);
 
        if (file) {
@@ -796,8 +803,11 @@ again:                     remove_next = 1 + (end > next->vm_end);
                 * up the code too much to do both in one go.
                 */
                next = vma->vm_next;
-               if (remove_next == 2)
+               if (remove_next == 2) {
+                       remove_next = 1;
+                       end = next->vm_end;
                        goto again;
+               }
                else if (next)
                        vma_gap_update(next);
                else
index d4a929d..7d0a275 100644 (file)
@@ -176,11 +176,13 @@ unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg,
 
        /*
         * Do not even consider tasks which are explicitly marked oom
-        * unkillable or have been already oom reaped.
+        * unkillable or have been already oom reaped or the are in
+        * the middle of vfork
         */
        adj = (long)p->signal->oom_score_adj;
        if (adj == OOM_SCORE_ADJ_MIN ||
-                       test_bit(MMF_OOM_REAPED, &p->mm->flags)) {
+                       test_bit(MMF_OOM_REAPED, &p->mm->flags) ||
+                       in_vfork(p)) {
                task_unlock(p);
                return 0;
        }
@@ -281,10 +283,22 @@ enum oom_scan_t oom_scan_process_thread(struct oom_control *oc,
 
        /*
         * This task already has access to memory reserves and is being killed.
-        * Don't allow any other task to have access to the reserves.
+        * Don't allow any other task to have access to the reserves unless
+        * the task has MMF_OOM_REAPED because chances that it would release
+        * any memory is quite low.
         */
-       if (!is_sysrq_oom(oc) && atomic_read(&task->signal->oom_victims))
-               return OOM_SCAN_ABORT;
+       if (!is_sysrq_oom(oc) && atomic_read(&task->signal->oom_victims)) {
+               struct task_struct *p = find_lock_task_mm(task);
+               enum oom_scan_t ret = OOM_SCAN_ABORT;
+
+               if (p) {
+                       if (test_bit(MMF_OOM_REAPED, &p->mm->flags))
+                               ret = OOM_SCAN_CONTINUE;
+                       task_unlock(p);
+               }
+
+               return ret;
+       }
 
        /*
         * If task is allocating a lot of memory and has been marked to be
@@ -415,7 +429,7 @@ bool oom_killer_disabled __read_mostly;
  * task's threads: if one of those is using this mm then this task was also
  * using it.
  */
-static bool process_shares_mm(struct task_struct *p, struct mm_struct *mm)
+bool process_shares_mm(struct task_struct *p, struct mm_struct *mm)
 {
        struct task_struct *t;
 
@@ -554,8 +568,27 @@ static void oom_reap_task(struct task_struct *tsk)
                schedule_timeout_idle(HZ/10);
 
        if (attempts > MAX_OOM_REAP_RETRIES) {
+               struct task_struct *p;
+
                pr_info("oom_reaper: unable to reap pid:%d (%s)\n",
                                task_pid_nr(tsk), tsk->comm);
+
+               /*
+                * If we've already tried to reap this task in the past and
+                * failed it probably doesn't make much sense to try yet again
+                * so hide the mm from the oom killer so that it can move on
+                * to another task with a different mm struct.
+                */
+               p = find_lock_task_mm(tsk);
+               if (p) {
+                       if (test_and_set_bit(MMF_OOM_NOT_REAPABLE, &p->mm->flags)) {
+                               pr_info("oom_reaper: giving up pid:%d (%s)\n",
+                                               task_pid_nr(tsk), tsk->comm);
+                               set_bit(MMF_OOM_REAPED, &p->mm->flags);
+                       }
+                       task_unlock(p);
+               }
+
                debug_show_all_locks();
        }
 
@@ -594,7 +627,7 @@ static int oom_reaper(void *unused)
        return 0;
 }
 
-static void wake_oom_reaper(struct task_struct *tsk)
+void wake_oom_reaper(struct task_struct *tsk)
 {
        if (!oom_reaper_th)
                return;
@@ -612,46 +645,6 @@ static void wake_oom_reaper(struct task_struct *tsk)
        wake_up(&oom_reaper_wait);
 }
 
-/* Check if we can reap the given task. This has to be called with stable
- * tsk->mm
- */
-void try_oom_reaper(struct task_struct *tsk)
-{
-       struct mm_struct *mm = tsk->mm;
-       struct task_struct *p;
-
-       if (!mm)
-               return;
-
-       /*
-        * There might be other threads/processes which are either not
-        * dying or even not killable.
-        */
-       if (atomic_read(&mm->mm_users) > 1) {
-               rcu_read_lock();
-               for_each_process(p) {
-                       if (!process_shares_mm(p, mm))
-                               continue;
-                       if (fatal_signal_pending(p))
-                               continue;
-
-                       /*
-                        * If the task is exiting make sure the whole thread group
-                        * is exiting and cannot acces mm anymore.
-                        */
-                       if (signal_group_exit(p->signal))
-                               continue;
-
-                       /* Give up */
-                       rcu_read_unlock();
-                       return;
-               }
-               rcu_read_unlock();
-       }
-
-       wake_oom_reaper(tsk);
-}
-
 static int __init oom_init(void)
 {
        oom_reaper_th = kthread_run(oom_reaper, NULL, "oom_reaper");
@@ -663,10 +656,6 @@ static int __init oom_init(void)
        return 0;
 }
 subsys_initcall(oom_init)
-#else
-static void wake_oom_reaper(struct task_struct *tsk)
-{
-}
 #endif
 
 /**
@@ -743,6 +732,80 @@ void oom_killer_enable(void)
        oom_killer_disabled = false;
 }
 
+static inline bool __task_will_free_mem(struct task_struct *task)
+{
+       struct signal_struct *sig = task->signal;
+
+       /*
+        * A coredumping process may sleep for an extended period in exit_mm(),
+        * so the oom killer cannot assume that the process will promptly exit
+        * and release memory.
+        */
+       if (sig->flags & SIGNAL_GROUP_COREDUMP)
+               return false;
+
+       if (sig->flags & SIGNAL_GROUP_EXIT)
+               return true;
+
+       if (thread_group_empty(task) && (task->flags & PF_EXITING))
+               return true;
+
+       return false;
+}
+
+/*
+ * Checks whether the given task is dying or exiting and likely to
+ * release its address space. This means that all threads and processes
+ * sharing the same mm have to be killed or exiting.
+ * Caller has to make sure that task->mm is stable (hold task_lock or
+ * it operates on the current).
+ */
+bool task_will_free_mem(struct task_struct *task)
+{
+       struct mm_struct *mm = task->mm;
+       struct task_struct *p;
+       bool ret;
+
+       /*
+        * Skip tasks without mm because it might have passed its exit_mm and
+        * exit_oom_victim. oom_reaper could have rescued that but do not rely
+        * on that for now. We can consider find_lock_task_mm in future.
+        */
+       if (!mm)
+               return false;
+
+       if (!__task_will_free_mem(task))
+               return false;
+
+       /*
+        * This task has already been drained by the oom reaper so there are
+        * only small chances it will free some more
+        */
+       if (test_bit(MMF_OOM_REAPED, &mm->flags))
+               return false;
+
+       if (atomic_read(&mm->mm_users) <= 1)
+               return true;
+
+       /*
+        * This is really pessimistic but we do not have any reliable way
+        * to check that external processes share with our mm
+        */
+       rcu_read_lock();
+       for_each_process(p) {
+               if (!process_shares_mm(p, mm))
+                       continue;
+               if (same_thread_group(task, p))
+                       continue;
+               ret = __task_will_free_mem(p);
+               if (!ret)
+                       break;
+       }
+       rcu_read_unlock();
+
+       return ret;
+}
+
 /*
  * Must be called while holding a reference to p, which will be released upon
  * returning.
@@ -765,9 +828,9 @@ void oom_kill_process(struct oom_control *oc, struct task_struct *p,
         * its children or threads, just set TIF_MEMDIE so it can die quickly
         */
        task_lock(p);
-       if (p->mm && task_will_free_mem(p)) {
+       if (task_will_free_mem(p)) {
                mark_oom_victim(p);
-               try_oom_reaper(p);
+               wake_oom_reaper(p);
                task_unlock(p);
                put_task_struct(p);
                return;
@@ -850,14 +913,18 @@ void oom_kill_process(struct oom_control *oc, struct task_struct *p,
                        continue;
                if (same_thread_group(p, victim))
                        continue;
-               if (unlikely(p->flags & PF_KTHREAD) || is_global_init(p) ||
-                   p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN) {
+               if (unlikely(p->flags & PF_KTHREAD) || is_global_init(p)) {
                        /*
                         * We cannot use oom_reaper for the mm shared by this
                         * process because it wouldn't get killed and so the
-                        * memory might be still used.
+                        * memory might be still used. Hide the mm from the oom
+                        * killer to guarantee OOM forward progress.
                         */
                        can_oom_reap = false;
+                       set_bit(MMF_OOM_REAPED, &mm->flags);
+                       pr_info("oom killer %d (%s) has mm pinned by %d (%s)\n",
+                                       task_pid_nr(victim), victim->comm,
+                                       task_pid_nr(p), p->comm);
                        continue;
                }
                do_send_sig_info(SIGKILL, SEND_SIG_FORCED, p, true);
@@ -939,14 +1006,10 @@ bool out_of_memory(struct oom_control *oc)
         * If current has a pending SIGKILL or is exiting, then automatically
         * select it.  The goal is to allow it to allocate so that it may
         * quickly exit and free its memory.
-        *
-        * But don't select if current has already released its mm and cleared
-        * TIF_MEMDIE flag at exit_mm(), otherwise an OOM livelock may occur.
         */
-       if (current->mm &&
-           (fatal_signal_pending(current) || task_will_free_mem(current))) {
+       if (task_will_free_mem(current)) {
                mark_oom_victim(current);
-               try_oom_reaper(current);
+               wake_oom_reaper(current);
                return true;
        }
 
index d578d2a..f4cd7d8 100644 (file)
@@ -267,26 +267,35 @@ static void wb_min_max_ratio(struct bdi_writeback *wb,
  */
 
 /**
- * zone_dirtyable_memory - number of dirtyable pages in a zone
- * @zone: the zone
+ * node_dirtyable_memory - number of dirtyable pages in a node
+ * @pgdat: the node
  *
- * Returns the zone's number of pages potentially available for dirty
- * page cache.  This is the base value for the per-zone dirty limits.
+ * Returns the node's number of pages potentially available for dirty
+ * page cache.  This is the base value for the per-node dirty limits.
  */
-static unsigned long zone_dirtyable_memory(struct zone *zone)
+static unsigned long node_dirtyable_memory(struct pglist_data *pgdat)
 {
-       unsigned long nr_pages;
+       unsigned long nr_pages = 0;
+       int z;
+
+       for (z = 0; z < MAX_NR_ZONES; z++) {
+               struct zone *zone = pgdat->node_zones + z;
+
+               if (!populated_zone(zone))
+                       continue;
+
+               nr_pages += zone_page_state(zone, NR_FREE_PAGES);
+       }
 
-       nr_pages = zone_page_state(zone, NR_FREE_PAGES);
        /*
         * Pages reserved for the kernel should not be considered
         * dirtyable, to prevent a situation where reclaim has to
         * clean pages in order to balance the zones.
         */
-       nr_pages -= min(nr_pages, zone->totalreserve_pages);
+       nr_pages -= min(nr_pages, pgdat->totalreserve_pages);
 
-       nr_pages += zone_page_state(zone, NR_INACTIVE_FILE);
-       nr_pages += zone_page_state(zone, NR_ACTIVE_FILE);
+       nr_pages += node_page_state(pgdat, NR_INACTIVE_FILE);
+       nr_pages += node_page_state(pgdat, NR_ACTIVE_FILE);
 
        return nr_pages;
 }
@@ -299,13 +308,26 @@ static unsigned long highmem_dirtyable_memory(unsigned long total)
        int i;
 
        for_each_node_state(node, N_HIGH_MEMORY) {
-               for (i = 0; i < MAX_NR_ZONES; i++) {
-                       struct zone *z = &NODE_DATA(node)->node_zones[i];
+               for (i = ZONE_NORMAL + 1; i < MAX_NR_ZONES; i++) {
+                       struct zone *z;
+                       unsigned long nr_pages;
+
+                       if (!is_highmem_idx(i))
+                               continue;
+
+                       z = &NODE_DATA(node)->node_zones[i];
+                       if (!populated_zone(z))
+                               continue;
 
-                       if (is_highmem(z))
-                               x += zone_dirtyable_memory(z);
+                       nr_pages = zone_page_state(z, NR_FREE_PAGES);
+                       /* watch for underflows */
+                       nr_pages -= min(nr_pages, high_wmark_pages(z));
+                       nr_pages += zone_page_state(z, NR_ZONE_INACTIVE_FILE);
+                       nr_pages += zone_page_state(z, NR_ZONE_ACTIVE_FILE);
+                       x += nr_pages;
                }
        }
+
        /*
         * Unreclaimable memory (kernel memory or anonymous memory
         * without swap) can bring down the dirtyable pages below
@@ -348,8 +370,8 @@ static unsigned long global_dirtyable_memory(void)
         */
        x -= min(x, totalreserve_pages);
 
-       x += global_page_state(NR_INACTIVE_FILE);
-       x += global_page_state(NR_ACTIVE_FILE);
+       x += global_node_page_state(NR_INACTIVE_FILE);
+       x += global_node_page_state(NR_ACTIVE_FILE);
 
        if (!vm_highmem_is_dirtyable)
                x -= highmem_dirtyable_memory(x);
@@ -445,23 +467,23 @@ void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty)
 }
 
 /**
- * zone_dirty_limit - maximum number of dirty pages allowed in a zone
- * @zone: the zone
+ * node_dirty_limit - maximum number of dirty pages allowed in a node
+ * @pgdat: the node
  *
- * Returns the maximum number of dirty pages allowed in a zone, based
- * on the zone's dirtyable memory.
+ * Returns the maximum number of dirty pages allowed in a node, based
+ * on the node's dirtyable memory.
  */
-static unsigned long zone_dirty_limit(struct zone *zone)
+static unsigned long node_dirty_limit(struct pglist_data *pgdat)
 {
-       unsigned long zone_memory = zone_dirtyable_memory(zone);
+       unsigned long node_memory = node_dirtyable_memory(pgdat);
        struct task_struct *tsk = current;
        unsigned long dirty;
 
        if (vm_dirty_bytes)
                dirty = DIV_ROUND_UP(vm_dirty_bytes, PAGE_SIZE) *
-                       zone_memory / global_dirtyable_memory();
+                       node_memory / global_dirtyable_memory();
        else
-               dirty = vm_dirty_ratio * zone_memory / 100;
+               dirty = vm_dirty_ratio * node_memory / 100;
 
        if (tsk->flags & PF_LESS_THROTTLE || rt_task(tsk))
                dirty += dirty / 4;
@@ -470,19 +492,22 @@ static unsigned long zone_dirty_limit(struct zone *zone)
 }
 
 /**
- * zone_dirty_ok - tells whether a zone is within its dirty limits
- * @zone: the zone to check
+ * node_dirty_ok - tells whether a node is within its dirty limits
+ * @pgdat: the node to check
  *
- * Returns %true when the dirty pages in @zone are within the zone's
+ * Returns %true when the dirty pages in @pgdat are within the node's
  * dirty limit, %false if the limit is exceeded.
  */
-bool zone_dirty_ok(struct zone *zone)
+bool node_dirty_ok(struct pglist_data *pgdat)
 {
-       unsigned long limit = zone_dirty_limit(zone);
+       unsigned long limit = node_dirty_limit(pgdat);
+       unsigned long nr_pages = 0;
+
+       nr_pages += node_page_state(pgdat, NR_FILE_DIRTY);
+       nr_pages += node_page_state(pgdat, NR_UNSTABLE_NFS);
+       nr_pages += node_page_state(pgdat, NR_WRITEBACK);
 
-       return zone_page_state(zone, NR_FILE_DIRTY) +
-              zone_page_state(zone, NR_UNSTABLE_NFS) +
-              zone_page_state(zone, NR_WRITEBACK) <= limit;
+       return nr_pages <= limit;
 }
 
 int dirty_background_ratio_handler(struct ctl_table *table, int write,
@@ -1570,10 +1595,10 @@ static void balance_dirty_pages(struct address_space *mapping,
                 * written to the server's write cache, but has not yet
                 * been flushed to permanent storage.
                 */
-               nr_reclaimable = global_page_state(NR_FILE_DIRTY) +
-                                       global_page_state(NR_UNSTABLE_NFS);
+               nr_reclaimable = global_node_page_state(NR_FILE_DIRTY) +
+                                       global_node_page_state(NR_UNSTABLE_NFS);
                gdtc->avail = global_dirtyable_memory();
-               gdtc->dirty = nr_reclaimable + global_page_state(NR_WRITEBACK);
+               gdtc->dirty = nr_reclaimable + global_node_page_state(NR_WRITEBACK);
 
                domain_dirty_limits(gdtc);
 
@@ -1910,8 +1935,8 @@ bool wb_over_bg_thresh(struct bdi_writeback *wb)
         * as we're trying to decide whether to put more under writeback.
         */
        gdtc->avail = global_dirtyable_memory();
-       gdtc->dirty = global_page_state(NR_FILE_DIRTY) +
-                     global_page_state(NR_UNSTABLE_NFS);
+       gdtc->dirty = global_node_page_state(NR_FILE_DIRTY) +
+                     global_node_page_state(NR_UNSTABLE_NFS);
        domain_dirty_limits(gdtc);
 
        if (gdtc->dirty > gdtc->bg_thresh)
@@ -1955,8 +1980,8 @@ void throttle_vm_writeout(gfp_t gfp_mask)
                  */
                 dirty_thresh += dirty_thresh / 10;      /* wheeee... */
 
-                if (global_page_state(NR_UNSTABLE_NFS) +
-                       global_page_state(NR_WRITEBACK) <= dirty_thresh)
+                if (global_node_page_state(NR_UNSTABLE_NFS) +
+                       global_node_page_state(NR_WRITEBACK) <= dirty_thresh)
                                break;
                 congestion_wait(BLK_RW_ASYNC, HZ/10);
 
@@ -1984,8 +2009,8 @@ int dirty_writeback_centisecs_handler(struct ctl_table *table, int write,
 void laptop_mode_timer_fn(unsigned long data)
 {
        struct request_queue *q = (struct request_queue *)data;
-       int nr_pages = global_page_state(NR_FILE_DIRTY) +
-               global_page_state(NR_UNSTABLE_NFS);
+       int nr_pages = global_node_page_state(NR_FILE_DIRTY) +
+               global_node_page_state(NR_UNSTABLE_NFS);
        struct bdi_writeback *wb;
 
        /*
@@ -2436,8 +2461,9 @@ void account_page_dirtied(struct page *page, struct address_space *mapping)
                wb = inode_to_wb(inode);
 
                mem_cgroup_inc_page_stat(page, MEM_CGROUP_STAT_DIRTY);
-               __inc_zone_page_state(page, NR_FILE_DIRTY);
-               __inc_zone_page_state(page, NR_DIRTIED);
+               __inc_node_page_state(page, NR_FILE_DIRTY);
+               __inc_zone_page_state(page, NR_ZONE_WRITE_PENDING);
+               __inc_node_page_state(page, NR_DIRTIED);
                __inc_wb_stat(wb, WB_RECLAIMABLE);
                __inc_wb_stat(wb, WB_DIRTIED);
                task_io_account_write(PAGE_SIZE);
@@ -2457,7 +2483,8 @@ void account_page_cleaned(struct page *page, struct address_space *mapping,
 {
        if (mapping_cap_account_dirty(mapping)) {
                mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_DIRTY);
-               dec_zone_page_state(page, NR_FILE_DIRTY);
+               dec_node_page_state(page, NR_FILE_DIRTY);
+               dec_zone_page_state(page, NR_ZONE_WRITE_PENDING);
                dec_wb_stat(wb, WB_RECLAIMABLE);
                task_io_account_cancelled_write(PAGE_SIZE);
        }
@@ -2525,7 +2552,7 @@ void account_page_redirty(struct page *page)
 
                wb = unlocked_inode_to_wb_begin(inode, &locked);
                current->nr_dirtied--;
-               dec_zone_page_state(page, NR_DIRTIED);
+               dec_node_page_state(page, NR_DIRTIED);
                dec_wb_stat(wb, WB_DIRTIED);
                unlocked_inode_to_wb_end(inode, locked);
        }
@@ -2713,7 +2740,8 @@ int clear_page_dirty_for_io(struct page *page)
                wb = unlocked_inode_to_wb_begin(inode, &locked);
                if (TestClearPageDirty(page)) {
                        mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_DIRTY);
-                       dec_zone_page_state(page, NR_FILE_DIRTY);
+                       dec_node_page_state(page, NR_FILE_DIRTY);
+                       dec_zone_page_state(page, NR_ZONE_WRITE_PENDING);
                        dec_wb_stat(wb, WB_RECLAIMABLE);
                        ret = 1;
                }
@@ -2759,8 +2787,9 @@ int test_clear_page_writeback(struct page *page)
        }
        if (ret) {
                mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_WRITEBACK);
-               dec_zone_page_state(page, NR_WRITEBACK);
-               inc_zone_page_state(page, NR_WRITTEN);
+               dec_node_page_state(page, NR_WRITEBACK);
+               dec_zone_page_state(page, NR_ZONE_WRITE_PENDING);
+               inc_node_page_state(page, NR_WRITTEN);
        }
        unlock_page_memcg(page);
        return ret;
@@ -2813,7 +2842,8 @@ int __test_set_page_writeback(struct page *page, bool keep_write)
        }
        if (!ret) {
                mem_cgroup_inc_page_stat(page, MEM_CGROUP_STAT_WRITEBACK);
-               inc_zone_page_state(page, NR_WRITEBACK);
+               inc_node_page_state(page, NR_WRITEBACK);
+               inc_zone_page_state(page, NR_ZONE_WRITE_PENDING);
        }
        unlock_page_memcg(page);
        return ret;
index 452513b..ea759b9 100644 (file)
@@ -295,14 +295,6 @@ static inline bool __meminit early_page_uninitialised(unsigned long pfn)
        return false;
 }
 
-static inline bool early_page_nid_uninitialised(unsigned long pfn, int nid)
-{
-       if (pfn >= NODE_DATA(nid)->first_deferred_pfn)
-               return true;
-
-       return false;
-}
-
 /*
  * Returns false when the remaining initialisation should be deferred until
  * later in the boot cycle when it can be parallelised.
@@ -342,11 +334,6 @@ static inline bool early_page_uninitialised(unsigned long pfn)
        return false;
 }
 
-static inline bool early_page_nid_uninitialised(unsigned long pfn, int nid)
-{
-       return false;
-}
-
 static inline bool update_defer_init(pg_data_t *pgdat,
                                unsigned long pfn, unsigned long zone_end,
                                unsigned long *nr_initialised)
@@ -1091,9 +1078,9 @@ static void free_pcppages_bulk(struct zone *zone, int count,
 
        spin_lock(&zone->lock);
        isolated_pageblocks = has_isolate_pageblock(zone);
-       nr_scanned = zone_page_state(zone, NR_PAGES_SCANNED);
+       nr_scanned = node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED);
        if (nr_scanned)
-               __mod_zone_page_state(zone, NR_PAGES_SCANNED, -nr_scanned);
+               __mod_node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED, -nr_scanned);
 
        while (count) {
                struct page *page;
@@ -1148,9 +1135,9 @@ static void free_one_page(struct zone *zone,
 {
        unsigned long nr_scanned;
        spin_lock(&zone->lock);
-       nr_scanned = zone_page_state(zone, NR_PAGES_SCANNED);
+       nr_scanned = node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED);
        if (nr_scanned)
-               __mod_zone_page_state(zone, NR_PAGES_SCANNED, -nr_scanned);
+               __mod_node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED, -nr_scanned);
 
        if (unlikely(has_isolate_pageblock(zone) ||
                is_migrate_isolate(migratetype))) {
@@ -2517,7 +2504,10 @@ int __isolate_free_page(struct page *page, unsigned int order)
        zone->free_area[order].nr_free--;
        rmv_page_order(page);
 
-       /* Set the pageblock if the isolated page is at least a pageblock */
+       /*
+        * Set the pageblock if the isolated page is at least half of a
+        * pageblock
+        */
        if (order >= pageblock_order - 1) {
                struct page *endpage = page + (1 << order) - 1;
                for (; page < endpage; page += pageblock_nr_pages) {
@@ -2597,7 +2587,6 @@ struct page *buffered_rmqueue(struct zone *preferred_zone,
                        else
                                page = list_first_entry(list, struct page, lru);
 
-                       __dec_zone_state(zone, NR_ALLOC_BATCH);
                        list_del(&page->lru);
                        pcp->count--;
 
@@ -2623,16 +2612,11 @@ struct page *buffered_rmqueue(struct zone *preferred_zone,
                spin_unlock(&zone->lock);
                if (!page)
                        goto failed;
-               __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order));
                __mod_zone_freepage_state(zone, -(1 << order),
                                          get_pcppage_migratetype(page));
        }
 
-       if (atomic_long_read(&zone->vm_stat[NR_ALLOC_BATCH]) <= 0 &&
-           !test_bit(ZONE_FAIR_DEPLETED, &zone->flags))
-               set_bit(ZONE_FAIR_DEPLETED, &zone->flags);
-
-       __count_zone_vm_events(PGALLOC, zone, 1 << order);
+       __count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order);
        zone_statistics(preferred_zone, zone, gfp_flags);
        local_irq_restore(flags);
 
@@ -2842,40 +2826,18 @@ bool zone_watermark_ok_safe(struct zone *z, unsigned int order,
 }
 
 #ifdef CONFIG_NUMA
-static bool zone_local(struct zone *local_zone, struct zone *zone)
-{
-       return local_zone->node == zone->node;
-}
-
 static bool zone_allows_reclaim(struct zone *local_zone, struct zone *zone)
 {
        return node_distance(zone_to_nid(local_zone), zone_to_nid(zone)) <
                                RECLAIM_DISTANCE;
 }
 #else  /* CONFIG_NUMA */
-static bool zone_local(struct zone *local_zone, struct zone *zone)
-{
-       return true;
-}
-
 static bool zone_allows_reclaim(struct zone *local_zone, struct zone *zone)
 {
        return true;
 }
 #endif /* CONFIG_NUMA */
 
-static void reset_alloc_batches(struct zone *preferred_zone)
-{
-       struct zone *zone = preferred_zone->zone_pgdat->node_zones;
-
-       do {
-               mod_zone_page_state(zone, NR_ALLOC_BATCH,
-                       high_wmark_pages(zone) - low_wmark_pages(zone) -
-                       atomic_long_read(&zone->vm_stat[NR_ALLOC_BATCH]));
-               clear_bit(ZONE_FAIR_DEPLETED, &zone->flags);
-       } while (zone++ != preferred_zone);
-}
-
 /*
  * get_page_from_freelist goes through the zonelist trying to allocate
  * a page.
@@ -2886,10 +2848,8 @@ get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,
 {
        struct zoneref *z = ac->preferred_zoneref;
        struct zone *zone;
-       bool fair_skipped = false;
-       bool apply_fair = (alloc_flags & ALLOC_FAIR);
+       struct pglist_data *last_pgdat_dirty_limit = NULL;
 
-zonelist_scan:
        /*
         * Scan zonelist, looking for a zone with enough free.
         * See also __cpuset_node_allowed() comment in kernel/cpuset.c.
@@ -2903,51 +2863,34 @@ zonelist_scan:
                        (alloc_flags & ALLOC_CPUSET) &&
                        !__cpuset_zone_allowed(zone, gfp_mask))
                                continue;
-               /*
-                * Distribute pages in proportion to the individual
-                * zone size to ensure fair page aging.  The zone a
-                * page was allocated in should have no effect on the
-                * time the page has in memory before being reclaimed.
-                */
-               if (apply_fair) {
-                       if (test_bit(ZONE_FAIR_DEPLETED, &zone->flags)) {
-                               fair_skipped = true;
-                               continue;
-                       }
-                       if (!zone_local(ac->preferred_zoneref->zone, zone)) {
-                               if (fair_skipped)
-                                       goto reset_fair;
-                               apply_fair = false;
-                       }
-               }
                /*
                 * When allocating a page cache page for writing, we
-                * want to get it from a zone that is within its dirty
-                * limit, such that no single zone holds more than its
+                * want to get it from a node that is within its dirty
+                * limit, such that no single node holds more than its
                 * proportional share of globally allowed dirty pages.
-                * The dirty limits take into account the zone's
+                * The dirty limits take into account the node's
                 * lowmem reserves and high watermark so that kswapd
                 * should be able to balance it without having to
                 * write pages from its LRU list.
                 *
-                * This may look like it could increase pressure on
-                * lower zones by failing allocations in higher zones
-                * before they are full.  But the pages that do spill
-                * over are limited as the lower zones are protected
-                * by this very same mechanism.  It should not become
-                * a practical burden to them.
-                *
                 * XXX: For now, allow allocations to potentially
-                * exceed the per-zone dirty limit in the slowpath
+                * exceed the per-node dirty limit in the slowpath
                 * (spread_dirty_pages unset) before going into reclaim,
                 * which is important when on a NUMA setup the allowed
-                * zones are together not big enough to reach the
+                * nodes are together not big enough to reach the
                 * global limit.  The proper fix for these situations
-                * will require awareness of zones in the
+                * will require awareness of nodes in the
                 * dirty-throttling and the flusher threads.
                 */
-               if (ac->spread_dirty_pages && !zone_dirty_ok(zone))
-                       continue;
+               if (ac->spread_dirty_pages) {
+                       if (last_pgdat_dirty_limit == zone->zone_pgdat)
+                               continue;
+
+                       if (!node_dirty_ok(zone->zone_pgdat)) {
+                               last_pgdat_dirty_limit = zone->zone_pgdat;
+                               continue;
+                       }
+               }
 
                mark = zone->watermark[alloc_flags & ALLOC_WMARK_MASK];
                if (!zone_watermark_fast(zone, order, mark,
@@ -2959,16 +2902,16 @@ zonelist_scan:
                        if (alloc_flags & ALLOC_NO_WATERMARKS)
                                goto try_this_zone;
 
-                       if (zone_reclaim_mode == 0 ||
+                       if (node_reclaim_mode == 0 ||
                            !zone_allows_reclaim(ac->preferred_zoneref->zone, zone))
                                continue;
 
-                       ret = zone_reclaim(zone, gfp_mask, order);
+                       ret = node_reclaim(zone->zone_pgdat, gfp_mask, order);
                        switch (ret) {
-                       case ZONE_RECLAIM_NOSCAN:
+                       case NODE_RECLAIM_NOSCAN:
                                /* did not scan */
                                continue;
-                       case ZONE_RECLAIM_FULL:
+                       case NODE_RECLAIM_FULL:
                                /* scanned but unreclaimable */
                                continue;
                        default:
@@ -2998,23 +2941,6 @@ try_this_zone:
                }
        }
 
-       /*
-        * The first pass makes sure allocations are spread fairly within the
-        * local node.  However, the local node might have free pages left
-        * after the fairness batches are exhausted, and remote zones haven't
-        * even been considered yet.  Try once more without fairness, and
-        * include remote zones now, before entering the slowpath and waking
-        * kswapd: prefer spilling to a remote zone over swapping locally.
-        */
-       if (fair_skipped) {
-reset_fair:
-               apply_fair = false;
-               fair_skipped = false;
-               reset_alloc_batches(ac->preferred_zoneref->zone);
-               z = ac->preferred_zoneref;
-               goto zonelist_scan;
-       }
-
        return NULL;
 }
 
@@ -3159,7 +3085,6 @@ out:
        return page;
 }
 
-
 /*
  * Maximum number of compaction retries wit a progress before OOM
  * killer is consider as the only way to move forward.
@@ -3171,17 +3096,16 @@ out:
 static struct page *
 __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
                unsigned int alloc_flags, const struct alloc_context *ac,
-               enum migrate_mode mode, enum compact_result *compact_result)
+               enum compact_priority prio, enum compact_result *compact_result)
 {
        struct page *page;
-       int contended_compaction;
 
        if (!order)
                return NULL;
 
        current->flags |= PF_MEMALLOC;
        *compact_result = try_to_compact_pages(gfp_mask, order, alloc_flags, ac,
-                                               mode, &contended_compaction);
+                                                                       prio);
        current->flags &= ~PF_MEMALLOC;
 
        if (*compact_result <= COMPACT_INACTIVE)
@@ -3193,8 +3117,7 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
         */
        count_vm_event(COMPACTSTALL);
 
-       page = get_page_from_freelist(gfp_mask, order,
-                                       alloc_flags & ~ALLOC_NO_WATERMARKS, ac);
+       page = get_page_from_freelist(gfp_mask, order, alloc_flags, ac);
 
        if (page) {
                struct zone *zone = page_zone(page);
@@ -3211,24 +3134,6 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
         */
        count_vm_event(COMPACTFAIL);
 
-       /*
-        * In all zones where compaction was attempted (and not
-        * deferred or skipped), lock contention has been detected.
-        * For THP allocation we do not want to disrupt the others
-        * so we fallback to base pages instead.
-        */
-       if (contended_compaction == COMPACT_CONTENDED_LOCK)
-               *compact_result = COMPACT_CONTENDED;
-
-       /*
-        * If compaction was aborted due to need_resched(), we do not
-        * want to further increase allocation latency, unless it is
-        * khugepaged trying to collapse.
-        */
-       if (contended_compaction == COMPACT_CONTENDED_SCHED
-               && !(current->flags & PF_KTHREAD))
-               *compact_result = COMPACT_CONTENDED;
-
        cond_resched();
 
        return NULL;
@@ -3236,7 +3141,8 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
 
 static inline bool
 should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
-                    enum compact_result compact_result, enum migrate_mode *migrate_mode,
+                    enum compact_result compact_result,
+                    enum compact_priority *compact_priority,
                     int compaction_retries)
 {
        int max_retries = MAX_COMPACT_RETRIES;
@@ -3247,11 +3153,11 @@ should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
        /*
         * compaction considers all the zone as desperately out of memory
         * so it doesn't really make much sense to retry except when the
-        * failure could be caused by weak migration mode.
+        * failure could be caused by insufficient priority
         */
        if (compaction_failed(compact_result)) {
-               if (*migrate_mode == MIGRATE_ASYNC) {
-                       *migrate_mode = MIGRATE_SYNC_LIGHT;
+               if (*compact_priority > MIN_COMPACT_PRIORITY) {
+                       (*compact_priority)--;
                        return true;
                }
                return false;
@@ -3285,7 +3191,7 @@ should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
 static inline struct page *
 __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
                unsigned int alloc_flags, const struct alloc_context *ac,
-               enum migrate_mode mode, enum compact_result *compact_result)
+               enum compact_priority prio, enum compact_result *compact_result)
 {
        *compact_result = COMPACT_SKIPPED;
        return NULL;
@@ -3294,7 +3200,7 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
 static inline bool
 should_compact_retry(struct alloc_context *ac, unsigned int order, int alloc_flags,
                     enum compact_result compact_result,
-                    enum migrate_mode *migrate_mode,
+                    enum compact_priority *compact_priority,
                     int compaction_retries)
 {
        struct zone *zone;
@@ -3362,8 +3268,7 @@ __alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order,
                return NULL;
 
 retry:
-       page = get_page_from_freelist(gfp_mask, order,
-                                       alloc_flags & ~ALLOC_NO_WATERMARKS, ac);
+       page = get_page_from_freelist(gfp_mask, order, alloc_flags, ac);
 
        /*
         * If an allocation failed after direct reclaim, it could be because
@@ -3384,10 +3289,14 @@ static void wake_all_kswapds(unsigned int order, const struct alloc_context *ac)
 {
        struct zoneref *z;
        struct zone *zone;
+       pg_data_t *last_pgdat = NULL;
 
        for_each_zone_zonelist_nodemask(zone, z, ac->zonelist,
-                                               ac->high_zoneidx, ac->nodemask)
-               wakeup_kswapd(zone, order, ac_classzone_idx(ac));
+                                       ac->high_zoneidx, ac->nodemask) {
+               if (last_pgdat != zone->zone_pgdat)
+                       wakeup_kswapd(zone, order, ac->high_zoneidx);
+               last_pgdat = zone->zone_pgdat;
+       }
 }
 
 static inline unsigned int
@@ -3421,16 +3330,6 @@ gfp_to_alloc_flags(gfp_t gfp_mask)
        } else if (unlikely(rt_task(current)) && !in_interrupt())
                alloc_flags |= ALLOC_HARDER;
 
-       if (likely(!(gfp_mask & __GFP_NOMEMALLOC))) {
-               if (gfp_mask & __GFP_MEMALLOC)
-                       alloc_flags |= ALLOC_NO_WATERMARKS;
-               else if (in_serving_softirq() && (current->flags & PF_MEMALLOC))
-                       alloc_flags |= ALLOC_NO_WATERMARKS;
-               else if (!in_interrupt() &&
-                               ((current->flags & PF_MEMALLOC) ||
-                                unlikely(test_thread_flag(TIF_MEMDIE))))
-                       alloc_flags |= ALLOC_NO_WATERMARKS;
-       }
 #ifdef CONFIG_CMA
        if (gfpflags_to_migratetype(gfp_mask) == MIGRATE_MOVABLE)
                alloc_flags |= ALLOC_CMA;
@@ -3440,12 +3339,19 @@ gfp_to_alloc_flags(gfp_t gfp_mask)
 
 bool gfp_pfmemalloc_allowed(gfp_t gfp_mask)
 {
-       return !!(gfp_to_alloc_flags(gfp_mask) & ALLOC_NO_WATERMARKS);
-}
+       if (unlikely(gfp_mask & __GFP_NOMEMALLOC))
+               return false;
 
-static inline bool is_thp_gfp_mask(gfp_t gfp_mask)
-{
-       return (gfp_mask & (GFP_TRANSHUGE | __GFP_KSWAPD_RECLAIM)) == GFP_TRANSHUGE;
+       if (gfp_mask & __GFP_MEMALLOC)
+               return true;
+       if (in_serving_softirq() && (current->flags & PF_MEMALLOC))
+               return true;
+       if (!in_interrupt() &&
+                       ((current->flags & PF_MEMALLOC) ||
+                        unlikely(test_thread_flag(TIF_MEMDIE))))
+               return true;
+
+       return false;
 }
 
 /*
@@ -3481,10 +3387,10 @@ should_reclaim_retry(gfp_t gfp_mask, unsigned order,
                return false;
 
        /*
-        * Keep reclaiming pages while there is a chance this will lead somewhere.
-        * If none of the target zones can satisfy our allocation request even
-        * if all reclaimable pages are considered then we are screwed and have
-        * to go OOM.
+        * Keep reclaiming pages while there is a chance this will lead
+        * somewhere.  If none of the target zones can satisfy our allocation
+        * request even if all reclaimable pages are considered then we are
+        * screwed and have to go OOM.
         */
        for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx,
                                        ac->nodemask) {
@@ -3509,14 +3415,12 @@ should_reclaim_retry(gfp_t gfp_mask, unsigned order,
                         * prevent from pre mature OOM
                         */
                        if (!did_some_progress) {
-                               unsigned long writeback;
-                               unsigned long dirty;
+                               unsigned long write_pending;
 
-                               writeback = zone_page_state_snapshot(zone,
-                                                                    NR_WRITEBACK);
-                               dirty = zone_page_state_snapshot(zone, NR_FILE_DIRTY);
+                               write_pending = zone_page_state_snapshot(zone,
+                                                       NR_ZONE_WRITE_PENDING);
 
-                               if (2*(writeback + dirty) > reclaimable) {
+                               if (2 * write_pending > reclaimable) {
                                        congestion_wait(BLK_RW_ASYNC, HZ/10);
                                        return true;
                                }
@@ -3551,7 +3455,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
        struct page *page = NULL;
        unsigned int alloc_flags;
        unsigned long did_some_progress;
-       enum migrate_mode migration_mode = MIGRATE_ASYNC;
+       enum compact_priority compact_priority = DEF_COMPACT_PRIORITY;
        enum compact_result compact_result;
        int compaction_retries = 0;
        int no_progress_loops = 0;
@@ -3575,42 +3479,88 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
                                (__GFP_ATOMIC|__GFP_DIRECT_RECLAIM)))
                gfp_mask &= ~__GFP_ATOMIC;
 
-retry:
+       /*
+        * The fast path uses conservative alloc_flags to succeed only until
+        * kswapd needs to be woken up, and to avoid the cost of setting up
+        * alloc_flags precisely. So we do that now.
+        */
+       alloc_flags = gfp_to_alloc_flags(gfp_mask);
+
        if (gfp_mask & __GFP_KSWAPD_RECLAIM)
                wake_all_kswapds(order, ac);
 
        /*
-        * OK, we're below the kswapd watermark and have kicked background
-        * reclaim. Now things get more complex, so set up alloc_flags according
-        * to how we want to proceed.
+        * The adjusted alloc_flags might result in immediate success, so try
+        * that first
         */
-       alloc_flags = gfp_to_alloc_flags(gfp_mask);
+       page = get_page_from_freelist(gfp_mask, order, alloc_flags, ac);
+       if (page)
+               goto got_pg;
+
+       /*
+        * For costly allocations, try direct compaction first, as it's likely
+        * that we have enough base pages and don't need to reclaim. Don't try
+        * that for allocations that are allowed to ignore watermarks, as the
+        * ALLOC_NO_WATERMARKS attempt didn't yet happen.
+        */
+       if (can_direct_reclaim && order > PAGE_ALLOC_COSTLY_ORDER &&
+               !gfp_pfmemalloc_allowed(gfp_mask)) {
+               page = __alloc_pages_direct_compact(gfp_mask, order,
+                                               alloc_flags, ac,
+                                               INIT_COMPACT_PRIORITY,
+                                               &compact_result);
+               if (page)
+                       goto got_pg;
+
+               /*
+                * Checks for costly allocations with __GFP_NORETRY, which
+                * includes THP page fault allocations
+                */
+               if (gfp_mask & __GFP_NORETRY) {
+                       /*
+                        * If compaction is deferred for high-order allocations,
+                        * it is because sync compaction recently failed. If
+                        * this is the case and the caller requested a THP
+                        * allocation, we do not want to heavily disrupt the
+                        * system, so we fail the allocation instead of entering
+                        * direct reclaim.
+                        */
+                       if (compact_result == COMPACT_DEFERRED)
+                               goto nopage;
+
+                       /*
+                        * Looks like reclaim/compaction is worth trying, but
+                        * sync compaction could be very expensive, so keep
+                        * using async compaction.
+                        */
+                       compact_priority = INIT_COMPACT_PRIORITY;
+               }
+       }
+
+retry:
+       /* Ensure kswapd doesn't accidentally go to sleep as long as we loop */
+       if (gfp_mask & __GFP_KSWAPD_RECLAIM)
+               wake_all_kswapds(order, ac);
+
+       if (gfp_pfmemalloc_allowed(gfp_mask))
+               alloc_flags = ALLOC_NO_WATERMARKS;
 
        /*
         * Reset the zonelist iterators if memory policies can be ignored.
         * These allocations are high priority and system rather than user
         * orientated.
         */
-       if ((alloc_flags & ALLOC_NO_WATERMARKS) || !(alloc_flags & ALLOC_CPUSET)) {
+       if (!(alloc_flags & ALLOC_CPUSET) || (alloc_flags & ALLOC_NO_WATERMARKS)) {
                ac->zonelist = node_zonelist(numa_node_id(), gfp_mask);
                ac->preferred_zoneref = first_zones_zonelist(ac->zonelist,
                                        ac->high_zoneidx, ac->nodemask);
        }
 
-       /* This is the last chance, in general, before the goto nopage. */
-       page = get_page_from_freelist(gfp_mask, order,
-                               alloc_flags & ~ALLOC_NO_WATERMARKS, ac);
+       /* Attempt with potentially adjusted zonelist and alloc_flags */
+       page = get_page_from_freelist(gfp_mask, order, alloc_flags, ac);
        if (page)
                goto got_pg;
 
-       /* Allocate without watermarks if the context allows */
-       if (alloc_flags & ALLOC_NO_WATERMARKS) {
-               page = get_page_from_freelist(gfp_mask, order,
-                                               ALLOC_NO_WATERMARKS, ac);
-               if (page)
-                       goto got_pg;
-       }
-
        /* Caller is not willing to reclaim, we can't balance anything */
        if (!can_direct_reclaim) {
                /*
@@ -3640,38 +3590,6 @@ retry:
        if (test_thread_flag(TIF_MEMDIE) && !(gfp_mask & __GFP_NOFAIL))
                goto nopage;
 
-       /*
-        * Try direct compaction. The first pass is asynchronous. Subsequent
-        * attempts after direct reclaim are synchronous
-        */
-       page = __alloc_pages_direct_compact(gfp_mask, order, alloc_flags, ac,
-                                       migration_mode,
-                                       &compact_result);
-       if (page)
-               goto got_pg;
-
-       /* Checks for THP-specific high-order allocations */
-       if (is_thp_gfp_mask(gfp_mask)) {
-               /*
-                * If compaction is deferred for high-order allocations, it is
-                * because sync compaction recently failed. If this is the case
-                * and the caller requested a THP allocation, we do not want
-                * to heavily disrupt the system, so we fail the allocation
-                * instead of entering direct reclaim.
-                */
-               if (compact_result == COMPACT_DEFERRED)
-                       goto nopage;
-
-               /*
-                * Compaction is contended so rather back off than cause
-                * excessive stalls.
-                */
-               if(compact_result == COMPACT_CONTENDED)
-                       goto nopage;
-       }
-
-       if (order && compaction_made_progress(compact_result))
-               compaction_retries++;
 
        /* Try direct reclaim and then allocating */
        page = __alloc_pages_direct_reclaim(gfp_mask, order, alloc_flags, ac,
@@ -3679,16 +3597,25 @@ retry:
        if (page)
                goto got_pg;
 
+       /* Try direct compaction and then allocating */
+       page = __alloc_pages_direct_compact(gfp_mask, order, alloc_flags, ac,
+                                       compact_priority, &compact_result);
+       if (page)
+               goto got_pg;
+
+       if (order && compaction_made_progress(compact_result))
+               compaction_retries++;
+
        /* Do not loop if specifically requested */
        if (gfp_mask & __GFP_NORETRY)
-               goto noretry;
+               goto nopage;
 
        /*
         * Do not retry costly high order allocations unless they are
         * __GFP_REPEAT
         */
        if (order > PAGE_ALLOC_COSTLY_ORDER && !(gfp_mask & __GFP_REPEAT))
-               goto noretry;
+               goto nopage;
 
        /*
         * Costly allocations might have made a progress but this doesn't mean
@@ -3712,7 +3639,7 @@ retry:
         */
        if (did_some_progress > 0 &&
                        should_compact_retry(ac, order, alloc_flags,
-                               compact_result, &migration_mode,
+                               compact_result, &compact_priority,
                                compaction_retries))
                goto retry;
 
@@ -3727,25 +3654,6 @@ retry:
                goto retry;
        }
 
-noretry:
-       /*
-        * High-order allocations do not necessarily loop after direct reclaim
-        * and reclaim/compaction depends on compaction being called after
-        * reclaim so call directly if necessary.
-        * It can become very expensive to allocate transparent hugepages at
-        * fault, so use asynchronous memory compaction for THP unless it is
-        * khugepaged trying to collapse. All other requests should tolerate
-        * at least light sync migration.
-        */
-       if (is_thp_gfp_mask(gfp_mask) && !(current->flags & PF_KTHREAD))
-               migration_mode = MIGRATE_ASYNC;
-       else
-               migration_mode = MIGRATE_SYNC_LIGHT;
-       page = __alloc_pages_direct_compact(gfp_mask, order, alloc_flags,
-                                           ac, migration_mode,
-                                           &compact_result);
-       if (page)
-               goto got_pg;
 nopage:
        warn_alloc_failed(gfp_mask, order, NULL);
 got_pg:
@@ -3761,7 +3669,7 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
 {
        struct page *page;
        unsigned int cpuset_mems_cookie;
-       unsigned int alloc_flags = ALLOC_WMARK_LOW|ALLOC_FAIR;
+       unsigned int alloc_flags = ALLOC_WMARK_LOW;
        gfp_t alloc_mask = gfp_mask; /* The gfp_t that was actually used for allocation */
        struct alloc_context ac = {
                .high_zoneidx = gfp_zone(gfp_mask),
@@ -4192,7 +4100,7 @@ EXPORT_SYMBOL_GPL(si_mem_available);
 void si_meminfo(struct sysinfo *val)
 {
        val->totalram = totalram_pages;
-       val->sharedram = global_page_state(NR_SHMEM);
+       val->sharedram = global_node_page_state(NR_SHMEM);
        val->freeram = global_page_state(NR_FREE_PAGES);
        val->bufferram = nr_blockdev_pages();
        val->totalhigh = totalhigh_pages;
@@ -4214,8 +4122,8 @@ void si_meminfo_node(struct sysinfo *val, int nid)
        for (zone_type = 0; zone_type < MAX_NR_ZONES; zone_type++)
                managed_pages += pgdat->node_zones[zone_type].managed_pages;
        val->totalram = managed_pages;
-       val->sharedram = node_page_state(nid, NR_SHMEM);
-       val->freeram = node_page_state(nid, NR_FREE_PAGES);
+       val->sharedram = node_page_state(pgdat, NR_SHMEM);
+       val->freeram = sum_zone_node_page_state(nid, NR_FREE_PAGES);
 #ifdef CONFIG_HIGHMEM
        for (zone_type = 0; zone_type < MAX_NR_ZONES; zone_type++) {
                struct zone *zone = &pgdat->node_zones[zone_type];
@@ -4298,6 +4206,7 @@ void show_free_areas(unsigned int filter)
        unsigned long free_pcp = 0;
        int cpu;
        struct zone *zone;
+       pg_data_t *pgdat;
 
        for_each_populated_zone(zone) {
                if (skip_free_areas_node(filter, zone_to_nid(zone)))
@@ -4312,35 +4221,74 @@ void show_free_areas(unsigned int filter)
                " unevictable:%lu dirty:%lu writeback:%lu unstable:%lu\n"
                " slab_reclaimable:%lu slab_unreclaimable:%lu\n"
                " mapped:%lu shmem:%lu pagetables:%lu bounce:%lu\n"
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-               " anon_thp: %lu shmem_thp: %lu shmem_pmdmapped: %lu\n"
-#endif
                " free:%lu free_pcp:%lu free_cma:%lu\n",
-               global_page_state(NR_ACTIVE_ANON),
-               global_page_state(NR_INACTIVE_ANON),
-               global_page_state(NR_ISOLATED_ANON),
-               global_page_state(NR_ACTIVE_FILE),
-               global_page_state(NR_INACTIVE_FILE),
-               global_page_state(NR_ISOLATED_FILE),
-               global_page_state(NR_UNEVICTABLE),
-               global_page_state(NR_FILE_DIRTY),
-               global_page_state(NR_WRITEBACK),
-               global_page_state(NR_UNSTABLE_NFS),
+               global_node_page_state(NR_ACTIVE_ANON),
+               global_node_page_state(NR_INACTIVE_ANON),
+               global_node_page_state(NR_ISOLATED_ANON),
+               global_node_page_state(NR_ACTIVE_FILE),
+               global_node_page_state(NR_INACTIVE_FILE),
+               global_node_page_state(NR_ISOLATED_FILE),
+               global_node_page_state(NR_UNEVICTABLE),
+               global_node_page_state(NR_FILE_DIRTY),
+               global_node_page_state(NR_WRITEBACK),
+               global_node_page_state(NR_UNSTABLE_NFS),
                global_page_state(NR_SLAB_RECLAIMABLE),
                global_page_state(NR_SLAB_UNRECLAIMABLE),
-               global_page_state(NR_FILE_MAPPED),
-               global_page_state(NR_SHMEM),
+               global_node_page_state(NR_FILE_MAPPED),
+               global_node_page_state(NR_SHMEM),
                global_page_state(NR_PAGETABLE),
                global_page_state(NR_BOUNCE),
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-               global_page_state(NR_ANON_THPS) * HPAGE_PMD_NR,
-               global_page_state(NR_SHMEM_THPS) * HPAGE_PMD_NR,
-               global_page_state(NR_SHMEM_PMDMAPPED) * HPAGE_PMD_NR,
-#endif
                global_page_state(NR_FREE_PAGES),
                free_pcp,
                global_page_state(NR_FREE_CMA_PAGES));
 
+       for_each_online_pgdat(pgdat) {
+               printk("Node %d"
+                       " active_anon:%lukB"
+                       " inactive_anon:%lukB"
+                       " active_file:%lukB"
+                       " inactive_file:%lukB"
+                       " unevictable:%lukB"
+                       " isolated(anon):%lukB"
+                       " isolated(file):%lukB"
+                       " mapped:%lukB"
+                       " dirty:%lukB"
+                       " writeback:%lukB"
+                       " shmem:%lukB"
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+                       " shmem_thp: %lukB"
+                       " shmem_pmdmapped: %lukB"
+                       " anon_thp: %lukB"
+#endif
+                       " writeback_tmp:%lukB"
+                       " unstable:%lukB"
+                       " pages_scanned:%lu"
+                       " all_unreclaimable? %s"
+                       "\n",
+                       pgdat->node_id,
+                       K(node_page_state(pgdat, NR_ACTIVE_ANON)),
+                       K(node_page_state(pgdat, NR_INACTIVE_ANON)),
+                       K(node_page_state(pgdat, NR_ACTIVE_FILE)),
+                       K(node_page_state(pgdat, NR_INACTIVE_FILE)),
+                       K(node_page_state(pgdat, NR_UNEVICTABLE)),
+                       K(node_page_state(pgdat, NR_ISOLATED_ANON)),
+                       K(node_page_state(pgdat, NR_ISOLATED_FILE)),
+                       K(node_page_state(pgdat, NR_FILE_MAPPED)),
+                       K(node_page_state(pgdat, NR_FILE_DIRTY)),
+                       K(node_page_state(pgdat, NR_WRITEBACK)),
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+                       K(node_page_state(pgdat, NR_SHMEM_THPS) * HPAGE_PMD_NR),
+                       K(node_page_state(pgdat, NR_SHMEM_PMDMAPPED)
+                                       * HPAGE_PMD_NR),
+                       K(node_page_state(pgdat, NR_ANON_THPS) * HPAGE_PMD_NR),
+#endif
+                       K(node_page_state(pgdat, NR_SHMEM)),
+                       K(node_page_state(pgdat, NR_WRITEBACK_TEMP)),
+                       K(node_page_state(pgdat, NR_UNSTABLE_NFS)),
+                       node_page_state(pgdat, NR_PAGES_SCANNED),
+                       !pgdat_reclaimable(pgdat) ? "yes" : "no");
+       }
+
        for_each_populated_zone(zone) {
                int i;
 
@@ -4362,72 +4310,41 @@ void show_free_areas(unsigned int filter)
                        " active_file:%lukB"
                        " inactive_file:%lukB"
                        " unevictable:%lukB"
-                       " isolated(anon):%lukB"
-                       " isolated(file):%lukB"
+                       " writepending:%lukB"
                        " present:%lukB"
                        " managed:%lukB"
                        " mlocked:%lukB"
-                       " dirty:%lukB"
-                       " writeback:%lukB"
-                       " mapped:%lukB"
-                       " shmem:%lukB"
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-                       " shmem_thp: %lukB"
-                       " shmem_pmdmapped: %lukB"
-                       " anon_thp: %lukB"
-#endif
                        " slab_reclaimable:%lukB"
                        " slab_unreclaimable:%lukB"
                        " kernel_stack:%lukB"
                        " pagetables:%lukB"
-                       " unstable:%lukB"
                        " bounce:%lukB"
                        " free_pcp:%lukB"
                        " local_pcp:%ukB"
                        " free_cma:%lukB"
-                       " writeback_tmp:%lukB"
-                       " pages_scanned:%lu"
-                       " all_unreclaimable? %s"
                        "\n",
                        zone->name,
                        K(zone_page_state(zone, NR_FREE_PAGES)),
                        K(min_wmark_pages(zone)),
                        K(low_wmark_pages(zone)),
                        K(high_wmark_pages(zone)),
-                       K(zone_page_state(zone, NR_ACTIVE_ANON)),
-                       K(zone_page_state(zone, NR_INACTIVE_ANON)),
-                       K(zone_page_state(zone, NR_ACTIVE_FILE)),
-                       K(zone_page_state(zone, NR_INACTIVE_FILE)),
-                       K(zone_page_state(zone, NR_UNEVICTABLE)),
-                       K(zone_page_state(zone, NR_ISOLATED_ANON)),
-                       K(zone_page_state(zone, NR_ISOLATED_FILE)),
+                       K(zone_page_state(zone, NR_ZONE_ACTIVE_ANON)),
+                       K(zone_page_state(zone, NR_ZONE_INACTIVE_ANON)),
+                       K(zone_page_state(zone, NR_ZONE_ACTIVE_FILE)),
+                       K(zone_page_state(zone, NR_ZONE_INACTIVE_FILE)),
+                       K(zone_page_state(zone, NR_ZONE_UNEVICTABLE)),
+                       K(zone_page_state(zone, NR_ZONE_WRITE_PENDING)),
                        K(zone->present_pages),
                        K(zone->managed_pages),
                        K(zone_page_state(zone, NR_MLOCK)),
-                       K(zone_page_state(zone, NR_FILE_DIRTY)),
-                       K(zone_page_state(zone, NR_WRITEBACK)),
-                       K(zone_page_state(zone, NR_FILE_MAPPED)),
-                       K(zone_page_state(zone, NR_SHMEM)),
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-                       K(zone_page_state(zone, NR_SHMEM_THPS) * HPAGE_PMD_NR),
-                       K(zone_page_state(zone, NR_SHMEM_PMDMAPPED)
-                                       * HPAGE_PMD_NR),
-                       K(zone_page_state(zone, NR_ANON_THPS) * HPAGE_PMD_NR),
-#endif
                        K(zone_page_state(zone, NR_SLAB_RECLAIMABLE)),
                        K(zone_page_state(zone, NR_SLAB_UNRECLAIMABLE)),
-                       zone_page_state(zone, NR_KERNEL_STACK) *
-                               THREAD_SIZE / 1024,
+                       zone_page_state(zone, NR_KERNEL_STACK_KB),
                        K(zone_page_state(zone, NR_PAGETABLE)),
-                       K(zone_page_state(zone, NR_UNSTABLE_NFS)),
                        K(zone_page_state(zone, NR_BOUNCE)),
                        K(free_pcp),
                        K(this_cpu_read(zone->pageset->pcp.count)),
-                       K(zone_page_state(zone, NR_FREE_CMA_PAGES)),
-                       K(zone_page_state(zone, NR_WRITEBACK_TEMP)),
-                       K(zone_page_state(zone, NR_PAGES_SCANNED)),
-                       (!zone_reclaimable(zone) ? "yes" : "no")
-                       );
+                       K(zone_page_state(zone, NR_FREE_CMA_PAGES)));
                printk("lowmem_reserve[]:");
                for (i = 0; i < MAX_NR_ZONES; i++)
                        printk(" %ld", zone->lowmem_reserve[i]);
@@ -4469,7 +4386,7 @@ void show_free_areas(unsigned int filter)
 
        hugetlb_show_meminfo();
 
-       printk("%ld total pagecache pages\n", global_page_state(NR_FILE_PAGES));
+       printk("%ld total pagecache pages\n", global_node_page_state(NR_FILE_PAGES));
 
        show_swap_cache_info();
 }
@@ -5340,6 +5257,11 @@ static void __meminit setup_zone_pageset(struct zone *zone)
        zone->pageset = alloc_percpu(struct per_cpu_pageset);
        for_each_possible_cpu(cpu)
                zone_pageset_init(zone, cpu);
+
+       if (!zone->zone_pgdat->per_cpu_nodestats) {
+               zone->zone_pgdat->per_cpu_nodestats =
+                       alloc_percpu(struct per_cpu_nodestat);
+       }
 }
 
 /*
@@ -5909,6 +5831,8 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat)
        init_waitqueue_head(&pgdat->kcompactd_wait);
 #endif
        pgdat_page_ext_init(pgdat);
+       spin_lock_init(&pgdat->lru_lock);
+       lruvec_init(node_lruvec(pgdat));
 
        for (j = 0; j < MAX_NR_ZONES; j++) {
                struct zone *zone = pgdat->node_zones + j;
@@ -5958,21 +5882,16 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat)
                zone->managed_pages = is_highmem_idx(j) ? realsize : freesize;
 #ifdef CONFIG_NUMA
                zone->node = nid;
-               zone->min_unmapped_pages = (freesize*sysctl_min_unmapped_ratio)
+               pgdat->min_unmapped_pages += (freesize*sysctl_min_unmapped_ratio)
                                                / 100;
-               zone->min_slab_pages = (freesize * sysctl_min_slab_ratio) / 100;
+               pgdat->min_slab_pages += (freesize * sysctl_min_slab_ratio) / 100;
 #endif
                zone->name = zone_names[j];
+               zone->zone_pgdat = pgdat;
                spin_lock_init(&zone->lock);
-               spin_lock_init(&zone->lru_lock);
                zone_seqlock_init(zone);
-               zone->zone_pgdat = pgdat;
                zone_pcp_init(zone);
 
-               /* For bootup, initialized properly in watermark setup */
-               mod_zone_page_state(zone, NR_ALLOC_BATCH, zone->managed_pages);
-
-               lruvec_init(&zone->lruvec);
                if (!size)
                        continue;
 
@@ -6038,11 +5957,12 @@ void __paginginit free_area_init_node(int nid, unsigned long *zones_size,
        unsigned long end_pfn = 0;
 
        /* pg_data_t should be reset to zero when it's allocated */
-       WARN_ON(pgdat->nr_zones || pgdat->classzone_idx);
+       WARN_ON(pgdat->nr_zones || pgdat->kswapd_classzone_idx);
 
        reset_deferred_meminit(pgdat);
        pgdat->node_id = nid;
        pgdat->node_start_pfn = node_start_pfn;
+       pgdat->per_cpu_nodestats = NULL;
 #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
        get_pfn_range_for_nid(nid, &start_pfn, &end_pfn);
        pr_info("Initmem setup node %d [mem %#018Lx-%#018Lx]\n", nid,
@@ -6699,6 +6619,9 @@ static void calculate_totalreserve_pages(void)
        enum zone_type i, j;
 
        for_each_online_pgdat(pgdat) {
+
+               pgdat->totalreserve_pages = 0;
+
                for (i = 0; i < MAX_NR_ZONES; i++) {
                        struct zone *zone = pgdat->node_zones + i;
                        long max = 0;
@@ -6715,7 +6638,7 @@ static void calculate_totalreserve_pages(void)
                        if (max > zone->managed_pages)
                                max = zone->managed_pages;
 
-                       zone->totalreserve_pages = max;
+                       pgdat->totalreserve_pages += max;
 
                        reserve_pages += max;
                }
@@ -6816,10 +6739,6 @@ static void __setup_per_zone_wmarks(void)
                zone->watermark[WMARK_LOW]  = min_wmark_pages(zone) + tmp;
                zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) + tmp * 2;
 
-               __mod_zone_page_state(zone, NR_ALLOC_BATCH,
-                       high_wmark_pages(zone) - low_wmark_pages(zone) -
-                       atomic_long_read(&zone->vm_stat[NR_ALLOC_BATCH]));
-
                spin_unlock_irqrestore(&zone->lock, flags);
        }
 
@@ -6930,6 +6849,7 @@ int watermark_scale_factor_sysctl_handler(struct ctl_table *table, int write,
 int sysctl_min_unmapped_ratio_sysctl_handler(struct ctl_table *table, int write,
        void __user *buffer, size_t *length, loff_t *ppos)
 {
+       struct pglist_data *pgdat;
        struct zone *zone;
        int rc;
 
@@ -6937,8 +6857,11 @@ int sysctl_min_unmapped_ratio_sysctl_handler(struct ctl_table *table, int write,
        if (rc)
                return rc;
 
+       for_each_online_pgdat(pgdat)
+               pgdat->min_slab_pages = 0;
+
        for_each_zone(zone)
-               zone->min_unmapped_pages = (zone->managed_pages *
+               zone->zone_pgdat->min_unmapped_pages += (zone->managed_pages *
                                sysctl_min_unmapped_ratio) / 100;
        return 0;
 }
@@ -6946,6 +6869,7 @@ int sysctl_min_unmapped_ratio_sysctl_handler(struct ctl_table *table, int write,
 int sysctl_min_slab_ratio_sysctl_handler(struct ctl_table *table, int write,
        void __user *buffer, size_t *length, loff_t *ppos)
 {
+       struct pglist_data *pgdat;
        struct zone *zone;
        int rc;
 
@@ -6953,8 +6877,11 @@ int sysctl_min_slab_ratio_sysctl_handler(struct ctl_table *table, int write,
        if (rc)
                return rc;
 
+       for_each_online_pgdat(pgdat)
+               pgdat->min_slab_pages = 0;
+
        for_each_zone(zone)
-               zone->min_slab_pages = (zone->managed_pages *
+               zone->zone_pgdat->min_slab_pages += (zone->managed_pages *
                                sysctl_min_slab_ratio) / 100;
        return 0;
 }
index 4ea9c4e..ae11aa9 100644 (file)
@@ -41,12 +41,12 @@ static struct page *page_idle_get_page(unsigned long pfn)
                return NULL;
 
        zone = page_zone(page);
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irq(zone_lru_lock(zone));
        if (unlikely(!PageLRU(page))) {
                put_page(page);
                page = NULL;
        }
-       spin_unlock_irq(&zone->lru_lock);
+       spin_unlock_irq(zone_lru_lock(zone));
        return page;
 }
 
index dcc5d37..fb1fa26 100644 (file)
@@ -166,6 +166,8 @@ int generic_swapfile_activate(struct swap_info_struct *sis,
                unsigned block_in_page;
                sector_t first_block;
 
+               cond_resched();
+
                first_block = bmap(inode, probe_block);
                if (first_block == 0)
                        goto bad_bmap;
index 8a13d9f..709bc83 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -27,7 +27,7 @@
  *         mapping->i_mmap_rwsem
  *           anon_vma->rwsem
  *             mm->page_table_lock or pte_lock
- *               zone->lru_lock (in mark_page_accessed, isolate_lru_page)
+ *               zone_lru_lock (in mark_page_accessed, isolate_lru_page)
  *               swap_lock (in swap_duplicate, swap_info_get)
  *                 mmlist_lock (in mmput, drain_mmlist and others)
  *                 mapping->private_lock (in __set_page_dirty_buffers)
@@ -1213,8 +1213,8 @@ void do_page_add_anon_rmap(struct page *page,
                 * disabled.
                 */
                if (compound)
-                       __inc_zone_page_state(page, NR_ANON_THPS);
-               __mod_zone_page_state(page_zone(page), NR_ANON_PAGES, nr);
+                       __inc_node_page_state(page, NR_ANON_THPS);
+               __mod_node_page_state(page_pgdat(page), NR_ANON_MAPPED, nr);
        }
        if (unlikely(PageKsm(page)))
                return;
@@ -1251,14 +1251,14 @@ void page_add_new_anon_rmap(struct page *page,
                VM_BUG_ON_PAGE(!PageTransHuge(page), page);
                /* increment count (starts at -1) */
                atomic_set(compound_mapcount_ptr(page), 0);
-               __inc_zone_page_state(page, NR_ANON_THPS);
+               __inc_node_page_state(page, NR_ANON_THPS);
        } else {
                /* Anon THP always mapped first with PMD */
                VM_BUG_ON_PAGE(PageTransCompound(page), page);
                /* increment count (starts at -1) */
                atomic_set(&page->_mapcount, 0);
        }
-       __mod_zone_page_state(page_zone(page), NR_ANON_PAGES, nr);
+       __mod_node_page_state(page_pgdat(page), NR_ANON_MAPPED, nr);
        __page_set_anon_rmap(page, vma, address, 1);
 }
 
@@ -1282,7 +1282,7 @@ void page_add_file_rmap(struct page *page, bool compound)
                if (!atomic_inc_and_test(compound_mapcount_ptr(page)))
                        goto out;
                VM_BUG_ON_PAGE(!PageSwapBacked(page), page);
-               __inc_zone_page_state(page, NR_SHMEM_PMDMAPPED);
+               __inc_node_page_state(page, NR_SHMEM_PMDMAPPED);
        } else {
                if (PageTransCompound(page)) {
                        VM_BUG_ON_PAGE(!PageLocked(page), page);
@@ -1293,7 +1293,7 @@ void page_add_file_rmap(struct page *page, bool compound)
                if (!atomic_inc_and_test(&page->_mapcount))
                        goto out;
        }
-       __mod_zone_page_state(page_zone(page), NR_FILE_MAPPED, nr);
+       __mod_node_page_state(page_pgdat(page), NR_FILE_MAPPED, nr);
        mem_cgroup_inc_page_stat(page, MEM_CGROUP_STAT_FILE_MAPPED);
 out:
        unlock_page_memcg(page);
@@ -1322,18 +1322,18 @@ static void page_remove_file_rmap(struct page *page, bool compound)
                if (!atomic_add_negative(-1, compound_mapcount_ptr(page)))
                        goto out;
                VM_BUG_ON_PAGE(!PageSwapBacked(page), page);
-               __dec_zone_page_state(page, NR_SHMEM_PMDMAPPED);
+               __dec_node_page_state(page, NR_SHMEM_PMDMAPPED);
        } else {
                if (!atomic_add_negative(-1, &page->_mapcount))
                        goto out;
        }
 
        /*
-        * We use the irq-unsafe __{inc|mod}_zone_page_stat because
+        * We use the irq-unsafe __{inc|mod}_zone_page_state because
         * these counters are not modified in interrupt context, and
         * pte lock(a spinlock) is held, which implies preemption disabled.
         */
-       __mod_zone_page_state(page_zone(page), NR_FILE_MAPPED, -nr);
+       __mod_node_page_state(page_pgdat(page), NR_FILE_MAPPED, -nr);
        mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_FILE_MAPPED);
 
        if (unlikely(PageMlocked(page)))
@@ -1356,7 +1356,7 @@ static void page_remove_anon_compound_rmap(struct page *page)
        if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
                return;
 
-       __dec_zone_page_state(page, NR_ANON_THPS);
+       __dec_node_page_state(page, NR_ANON_THPS);
 
        if (TestClearPageDoubleMap(page)) {
                /*
@@ -1375,7 +1375,7 @@ static void page_remove_anon_compound_rmap(struct page *page)
                clear_page_mlock(page);
 
        if (nr) {
-               __mod_zone_page_state(page_zone(page), NR_ANON_PAGES, -nr);
+               __mod_node_page_state(page_pgdat(page), NR_ANON_MAPPED, -nr);
                deferred_split_huge_page(page);
        }
 }
@@ -1404,7 +1404,7 @@ void page_remove_rmap(struct page *page, bool compound)
         * these counters are not modified in interrupt context, and
         * pte lock(a spinlock) is held, which implies preemption disabled.
         */
-       __dec_zone_page_state(page, NR_ANON_PAGES);
+       __dec_node_page_state(page, NR_ANON_MAPPED);
 
        if (unlikely(PageMlocked(page)))
                clear_page_mlock(page);
index 62e42c7..2ac19a6 100644 (file)
@@ -575,9 +575,9 @@ static int shmem_add_to_page_cache(struct page *page,
        if (!error) {
                mapping->nrpages += nr;
                if (PageTransHuge(page))
-                       __inc_zone_page_state(page, NR_SHMEM_THPS);
-               __mod_zone_page_state(page_zone(page), NR_FILE_PAGES, nr);
-               __mod_zone_page_state(page_zone(page), NR_SHMEM, nr);
+                       __inc_node_page_state(page, NR_SHMEM_THPS);
+               __mod_node_page_state(page_pgdat(page), NR_FILE_PAGES, nr);
+               __mod_node_page_state(page_pgdat(page), NR_SHMEM, nr);
                spin_unlock_irq(&mapping->tree_lock);
        } else {
                page->mapping = NULL;
@@ -601,8 +601,8 @@ static void shmem_delete_from_page_cache(struct page *page, void *radswap)
        error = shmem_radix_tree_replace(mapping, page->index, page, radswap);
        page->mapping = NULL;
        mapping->nrpages--;
-       __dec_zone_page_state(page, NR_FILE_PAGES);
-       __dec_zone_page_state(page, NR_SHMEM);
+       __dec_node_page_state(page, NR_FILE_PAGES);
+       __dec_node_page_state(page, NR_SHMEM);
        spin_unlock_irq(&mapping->tree_lock);
        put_page(page);
        BUG_ON(error);
@@ -1493,8 +1493,8 @@ static int shmem_replace_page(struct page **pagep, gfp_t gfp,
        error = shmem_radix_tree_replace(swap_mapping, swap_index, oldpage,
                                                                   newpage);
        if (!error) {
-               __inc_zone_page_state(newpage, NR_FILE_PAGES);
-               __dec_zone_page_state(oldpage, NR_FILE_PAGES);
+               __inc_node_page_state(newpage, NR_FILE_PAGES);
+               __dec_node_page_state(oldpage, NR_FILE_PAGES);
        }
        spin_unlock_irq(&swap_mapping->tree_lock);
 
index f33980a..9653f2e 100644 (file)
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -369,6 +369,8 @@ static inline size_t slab_ksize(const struct kmem_cache *s)
        if (s->flags & (SLAB_RED_ZONE | SLAB_POISON))
                return s->object_size;
 # endif
+       if (s->flags & SLAB_KASAN)
+               return s->object_size;
        /*
         * If we have the need to store the freelist pointer
         * back there or track user information then we can
index f9da871..74e7c8c 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -124,7 +124,7 @@ static inline int kmem_cache_debug(struct kmem_cache *s)
 #endif
 }
 
-static inline void *fixup_red_left(struct kmem_cache *s, void *p)
+inline void *fixup_red_left(struct kmem_cache *s, void *p)
 {
        if (kmem_cache_debug(s) && s->flags & SLAB_RED_ZONE)
                p += s->red_left_pad;
@@ -454,8 +454,6 @@ static inline void *restore_red_left(struct kmem_cache *s, void *p)
  */
 #if defined(CONFIG_SLUB_DEBUG_ON)
 static int slub_debug = DEBUG_DEFAULT_FLAGS;
-#elif defined(CONFIG_KASAN)
-static int slub_debug = SLAB_STORE_USER;
 #else
 static int slub_debug;
 #endif
@@ -660,6 +658,8 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p)
        if (s->flags & SLAB_STORE_USER)
                off += 2 * sizeof(struct track);
 
+       off += kasan_metadata_size(s);
+
        if (off != size_from_object(s))
                /* Beginning of the filler is the free pointer */
                print_section("Padding ", p + off, size_from_object(s) - off);
@@ -787,6 +787,8 @@ static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p)
                /* We also have user information there */
                off += 2 * sizeof(struct track);
 
+       off += kasan_metadata_size(s);
+
        if (size_from_object(s) == off)
                return 1;
 
@@ -1322,8 +1324,10 @@ static inline void kfree_hook(const void *x)
        kasan_kfree_large(x);
 }
 
-static inline void slab_free_hook(struct kmem_cache *s, void *x)
+static inline void *slab_free_hook(struct kmem_cache *s, void *x)
 {
+       void *freeptr;
+
        kmemleak_free_recursive(x, s->flags);
 
        /*
@@ -1344,7 +1348,13 @@ static inline void slab_free_hook(struct kmem_cache *s, void *x)
        if (!(s->flags & SLAB_DEBUG_OBJECTS))
                debug_check_no_obj_freed(x, s->object_size);
 
+       freeptr = get_freepointer(s, x);
+       /*
+        * kasan_slab_free() may put x into memory quarantine, delaying its
+        * reuse. In this case the object's freelist pointer is changed.
+        */
        kasan_slab_free(s, x);
+       return freeptr;
 }
 
 static inline void slab_free_freelist_hook(struct kmem_cache *s,
@@ -1362,11 +1372,11 @@ static inline void slab_free_freelist_hook(struct kmem_cache *s,
 
        void *object = head;
        void *tail_obj = tail ? : head;
+       void *freeptr;
 
        do {
-               slab_free_hook(s, object);
-       } while ((object != tail_obj) &&
-                (object = get_freepointer(s, object)));
+               freeptr = slab_free_hook(s, object);
+       } while ((object != tail_obj) && (object = freeptr));
 #endif
 }
 
@@ -2878,16 +2888,13 @@ slab_empty:
  * same page) possible by specifying head and tail ptr, plus objects
  * count (cnt). Bulk free indicated by tail pointer being set.
  */
-static __always_inline void slab_free(struct kmem_cache *s, struct page *page,
-                                     void *head, void *tail, int cnt,
-                                     unsigned long addr)
+static __always_inline void do_slab_free(struct kmem_cache *s,
+                               struct page *page, void *head, void *tail,
+                               int cnt, unsigned long addr)
 {
        void *tail_obj = tail ? : head;
        struct kmem_cache_cpu *c;
        unsigned long tid;
-
-       slab_free_freelist_hook(s, head, tail);
-
 redo:
        /*
         * Determine the currently cpus per cpu slab.
@@ -2921,6 +2928,27 @@ redo:
 
 }
 
+static __always_inline void slab_free(struct kmem_cache *s, struct page *page,
+                                     void *head, void *tail, int cnt,
+                                     unsigned long addr)
+{
+       slab_free_freelist_hook(s, head, tail);
+       /*
+        * slab_free_freelist_hook() could have put the items into quarantine.
+        * If so, no need to free them.
+        */
+       if (s->flags & SLAB_KASAN && !(s->flags & SLAB_DESTROY_BY_RCU))
+               return;
+       do_slab_free(s, page, head, tail, cnt, addr);
+}
+
+#ifdef CONFIG_KASAN
+void ___cache_free(struct kmem_cache *cache, void *x, unsigned long addr)
+{
+       do_slab_free(cache, virt_to_head_page(x), x, NULL, 1, addr);
+}
+#endif
+
 void kmem_cache_free(struct kmem_cache *s, void *x)
 {
        s = cache_from_obj(s, x);
@@ -3363,7 +3391,7 @@ static void set_min_partial(struct kmem_cache *s, unsigned long min)
 static int calculate_sizes(struct kmem_cache *s, int forced_order)
 {
        unsigned long flags = s->flags;
-       unsigned long size = s->object_size;
+       size_t size = s->object_size;
        int order;
 
        /*
@@ -3422,7 +3450,10 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
                 * the object.
                 */
                size += 2 * sizeof(struct track);
+#endif
 
+       kasan_cache_create(s, &size, &s->flags);
+#ifdef CONFIG_SLUB_DEBUG
        if (flags & SLAB_RED_ZONE) {
                /*
                 * Add some empty padding so that we can catch
index 5d0cf45..36d7bbb 100644 (file)
@@ -100,11 +100,7 @@ static inline int sparse_index_init(unsigned long section_nr, int nid)
 }
 #endif
 
-/*
- * Although written for the SPARSEMEM_EXTREME case, this happens
- * to also work for the flat array case because
- * NR_SECTION_ROOTS==NR_MEM_SECTIONS.
- */
+#ifdef CONFIG_SPARSEMEM_EXTREME
 int __section_nr(struct mem_section* ms)
 {
        unsigned long root_nr;
@@ -123,6 +119,12 @@ int __section_nr(struct mem_section* ms)
 
        return (root_nr * SECTIONS_PER_ROOT) + (ms - root);
 }
+#else
+int __section_nr(struct mem_section* ms)
+{
+       return (int)(ms - mem_section[0]);
+}
+#endif
 
 /*
  * During early boot, before section_mem_map is used for an actual
index 616df4d..75c63bb 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -62,12 +62,12 @@ static void __page_cache_release(struct page *page)
                struct lruvec *lruvec;
                unsigned long flags;
 
-               spin_lock_irqsave(&zone->lru_lock, flags);
-               lruvec = mem_cgroup_page_lruvec(page, zone);
+               spin_lock_irqsave(zone_lru_lock(zone), flags);
+               lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat);
                VM_BUG_ON_PAGE(!PageLRU(page), page);
                __ClearPageLRU(page);
                del_page_from_lru_list(page, lruvec, page_off_lru(page));
-               spin_unlock_irqrestore(&zone->lru_lock, flags);
+               spin_unlock_irqrestore(zone_lru_lock(zone), flags);
        }
        mem_cgroup_uncharge(page);
 }
@@ -179,26 +179,26 @@ static void pagevec_lru_move_fn(struct pagevec *pvec,
        void *arg)
 {
        int i;
-       struct zone *zone = NULL;
+       struct pglist_data *pgdat = NULL;
        struct lruvec *lruvec;
        unsigned long flags = 0;
 
        for (i = 0; i < pagevec_count(pvec); i++) {
                struct page *page = pvec->pages[i];
-               struct zone *pagezone = page_zone(page);
+               struct pglist_data *pagepgdat = page_pgdat(page);
 
-               if (pagezone != zone) {
-                       if (zone)
-                               spin_unlock_irqrestore(&zone->lru_lock, flags);
-                       zone = pagezone;
-                       spin_lock_irqsave(&zone->lru_lock, flags);
+               if (pagepgdat != pgdat) {
+                       if (pgdat)
+                               spin_unlock_irqrestore(&pgdat->lru_lock, flags);
+                       pgdat = pagepgdat;
+                       spin_lock_irqsave(&pgdat->lru_lock, flags);
                }
 
-               lruvec = mem_cgroup_page_lruvec(page, zone);
+               lruvec = mem_cgroup_page_lruvec(page, pgdat);
                (*move_fn)(page, lruvec, arg);
        }
-       if (zone)
-               spin_unlock_irqrestore(&zone->lru_lock, flags);
+       if (pgdat)
+               spin_unlock_irqrestore(&pgdat->lru_lock, flags);
        release_pages(pvec->pages, pvec->nr, pvec->cold);
        pagevec_reinit(pvec);
 }
@@ -318,9 +318,9 @@ void activate_page(struct page *page)
        struct zone *zone = page_zone(page);
 
        page = compound_head(page);
-       spin_lock_irq(&zone->lru_lock);
-       __activate_page(page, mem_cgroup_page_lruvec(page, zone), NULL);
-       spin_unlock_irq(&zone->lru_lock);
+       spin_lock_irq(zone_lru_lock(zone));
+       __activate_page(page, mem_cgroup_page_lruvec(page, zone->zone_pgdat), NULL);
+       spin_unlock_irq(zone_lru_lock(zone));
 }
 #endif
 
@@ -445,16 +445,16 @@ void lru_cache_add(struct page *page)
  */
 void add_page_to_unevictable_list(struct page *page)
 {
-       struct zone *zone = page_zone(page);
+       struct pglist_data *pgdat = page_pgdat(page);
        struct lruvec *lruvec;
 
-       spin_lock_irq(&zone->lru_lock);
-       lruvec = mem_cgroup_page_lruvec(page, zone);
+       spin_lock_irq(&pgdat->lru_lock);
+       lruvec = mem_cgroup_page_lruvec(page, pgdat);
        ClearPageActive(page);
        SetPageUnevictable(page);
        SetPageLRU(page);
        add_page_to_lru_list(page, lruvec, LRU_UNEVICTABLE);
-       spin_unlock_irq(&zone->lru_lock);
+       spin_unlock_irq(&pgdat->lru_lock);
 }
 
 /**
@@ -730,7 +730,7 @@ void release_pages(struct page **pages, int nr, bool cold)
 {
        int i;
        LIST_HEAD(pages_to_free);
-       struct zone *zone = NULL;
+       struct pglist_data *locked_pgdat = NULL;
        struct lruvec *lruvec;
        unsigned long uninitialized_var(flags);
        unsigned int uninitialized_var(lock_batch);
@@ -741,11 +741,11 @@ void release_pages(struct page **pages, int nr, bool cold)
                /*
                 * Make sure the IRQ-safe lock-holding time does not get
                 * excessive with a continuous string of pages from the
-                * same zone. The lock is held only if zone != NULL.
+                * same pgdat. The lock is held only if pgdat != NULL.
                 */
-               if (zone && ++lock_batch == SWAP_CLUSTER_MAX) {
-                       spin_unlock_irqrestore(&zone->lru_lock, flags);
-                       zone = NULL;
+               if (locked_pgdat && ++lock_batch == SWAP_CLUSTER_MAX) {
+                       spin_unlock_irqrestore(&locked_pgdat->lru_lock, flags);
+                       locked_pgdat = NULL;
                }
 
                if (is_huge_zero_page(page)) {
@@ -758,27 +758,27 @@ void release_pages(struct page **pages, int nr, bool cold)
                        continue;
 
                if (PageCompound(page)) {
-                       if (zone) {
-                               spin_unlock_irqrestore(&zone->lru_lock, flags);
-                               zone = NULL;
+                       if (locked_pgdat) {
+                               spin_unlock_irqrestore(&locked_pgdat->lru_lock, flags);
+                               locked_pgdat = NULL;
                        }
                        __put_compound_page(page);
                        continue;
                }
 
                if (PageLRU(page)) {
-                       struct zone *pagezone = page_zone(page);
+                       struct pglist_data *pgdat = page_pgdat(page);
 
-                       if (pagezone != zone) {
-                               if (zone)
-                                       spin_unlock_irqrestore(&zone->lru_lock,
+                       if (pgdat != locked_pgdat) {
+                               if (locked_pgdat)
+                                       spin_unlock_irqrestore(&locked_pgdat->lru_lock,
                                                                        flags);
                                lock_batch = 0;
-                               zone = pagezone;
-                               spin_lock_irqsave(&zone->lru_lock, flags);
+                               locked_pgdat = pgdat;
+                               spin_lock_irqsave(&locked_pgdat->lru_lock, flags);
                        }
 
-                       lruvec = mem_cgroup_page_lruvec(page, zone);
+                       lruvec = mem_cgroup_page_lruvec(page, locked_pgdat);
                        VM_BUG_ON_PAGE(!PageLRU(page), page);
                        __ClearPageLRU(page);
                        del_page_from_lru_list(page, lruvec, page_off_lru(page));
@@ -789,8 +789,8 @@ void release_pages(struct page **pages, int nr, bool cold)
 
                list_add(&page->lru, &pages_to_free);
        }
-       if (zone)
-               spin_unlock_irqrestore(&zone->lru_lock, flags);
+       if (locked_pgdat)
+               spin_unlock_irqrestore(&locked_pgdat->lru_lock, flags);
 
        mem_cgroup_uncharge_list(&pages_to_free);
        free_hot_cold_page_list(&pages_to_free, cold);
@@ -826,7 +826,7 @@ void lru_add_page_tail(struct page *page, struct page *page_tail,
        VM_BUG_ON_PAGE(PageCompound(page_tail), page);
        VM_BUG_ON_PAGE(PageLRU(page_tail), page);
        VM_BUG_ON(NR_CPUS != 1 &&
-                 !spin_is_locked(&lruvec_zone(lruvec)->lru_lock));
+                 !spin_is_locked(&lruvec_pgdat(lruvec)->lru_lock));
 
        if (!list)
                SetPageLRU(page_tail);
index c99463a..c8310a3 100644 (file)
@@ -95,7 +95,7 @@ int __add_to_swap_cache(struct page *page, swp_entry_t entry)
                                        entry.val, page);
        if (likely(!error)) {
                address_space->nrpages++;
-               __inc_zone_page_state(page, NR_FILE_PAGES);
+               __inc_node_page_state(page, NR_FILE_PAGES);
                INC_CACHE_INFO(add_total);
        }
        spin_unlock_irq(&address_space->tree_lock);
@@ -147,7 +147,7 @@ void __delete_from_swap_cache(struct page *page)
        set_page_private(page, 0);
        ClearPageSwapCache(page);
        address_space->nrpages--;
-       __dec_zone_page_state(page, NR_FILE_PAGES);
+       __dec_node_page_state(page, NR_FILE_PAGES);
        INC_CACHE_INFO(del_total);
 }
 
index 8d010ef..662cddf 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -528,7 +528,7 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
 
        if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) {
                free = global_page_state(NR_FREE_PAGES);
-               free += global_page_state(NR_FILE_PAGES);
+               free += global_node_page_state(NR_FILE_PAGES);
 
                /*
                 * shmem pages shouldn't be counted as free in this
@@ -536,7 +536,7 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
                 * that won't affect the overall amount of available
                 * memory in the system.
                 */
-               free -= global_page_state(NR_SHMEM);
+               free -= global_node_page_state(NR_SHMEM);
 
                free += get_nr_swap_pages();
 
index 21d417c..650d268 100644 (file)
@@ -84,6 +84,9 @@ struct scan_control {
        /* Scan (total_size >> priority) pages at once */
        int priority;
 
+       /* The highest zone to isolate pages for reclaim from */
+       enum zone_type reclaim_idx;
+
        unsigned int may_writepage:1;
 
        /* Can mapped pages be reclaimed? */
@@ -191,26 +194,44 @@ static bool sane_reclaim(struct scan_control *sc)
 }
 #endif
 
+/*
+ * This misses isolated pages which are not accounted for to save counters.
+ * As the data only determines if reclaim or compaction continues, it is
+ * not expected that isolated pages will be a dominating factor.
+ */
 unsigned long zone_reclaimable_pages(struct zone *zone)
 {
        unsigned long nr;
 
-       nr = zone_page_state_snapshot(zone, NR_ACTIVE_FILE) +
-            zone_page_state_snapshot(zone, NR_INACTIVE_FILE) +
-            zone_page_state_snapshot(zone, NR_ISOLATED_FILE);
+       nr = zone_page_state_snapshot(zone, NR_ZONE_INACTIVE_FILE) +
+               zone_page_state_snapshot(zone, NR_ZONE_ACTIVE_FILE);
+       if (get_nr_swap_pages() > 0)
+               nr += zone_page_state_snapshot(zone, NR_ZONE_INACTIVE_ANON) +
+                       zone_page_state_snapshot(zone, NR_ZONE_ACTIVE_ANON);
+
+       return nr;
+}
+
+unsigned long pgdat_reclaimable_pages(struct pglist_data *pgdat)
+{
+       unsigned long nr;
+
+       nr = node_page_state_snapshot(pgdat, NR_ACTIVE_FILE) +
+            node_page_state_snapshot(pgdat, NR_INACTIVE_FILE) +
+            node_page_state_snapshot(pgdat, NR_ISOLATED_FILE);
 
        if (get_nr_swap_pages() > 0)
-               nr += zone_page_state_snapshot(zone, NR_ACTIVE_ANON) +
-                     zone_page_state_snapshot(zone, NR_INACTIVE_ANON) +
-                     zone_page_state_snapshot(zone, NR_ISOLATED_ANON);
+               nr += node_page_state_snapshot(pgdat, NR_ACTIVE_ANON) +
+                     node_page_state_snapshot(pgdat, NR_INACTIVE_ANON) +
+                     node_page_state_snapshot(pgdat, NR_ISOLATED_ANON);
 
        return nr;
 }
 
-bool zone_reclaimable(struct zone *zone)
+bool pgdat_reclaimable(struct pglist_data *pgdat)
 {
-       return zone_page_state_snapshot(zone, NR_PAGES_SCANNED) <
-               zone_reclaimable_pages(zone) * 6;
+       return node_page_state_snapshot(pgdat, NR_PAGES_SCANNED) <
+               pgdat_reclaimable_pages(pgdat) * 6;
 }
 
 unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru)
@@ -218,7 +239,7 @@ unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru)
        if (!mem_cgroup_disabled())
                return mem_cgroup_get_lru_size(lruvec, lru);
 
-       return zone_page_state(lruvec_zone(lruvec), NR_LRU_BASE + lru);
+       return node_page_state(lruvec_pgdat(lruvec), NR_LRU_BASE + lru);
 }
 
 /*
@@ -593,7 +614,7 @@ static pageout_t pageout(struct page *page, struct address_space *mapping,
                        ClearPageReclaim(page);
                }
                trace_mm_vmscan_writepage(page);
-               inc_zone_page_state(page, NR_VMSCAN_WRITE);
+               inc_node_page_state(page, NR_VMSCAN_WRITE);
                return PAGE_SUCCESS;
        }
 
@@ -877,7 +898,7 @@ static void page_check_dirty_writeback(struct page *page,
  * shrink_page_list() returns the number of reclaimed pages
  */
 static unsigned long shrink_page_list(struct list_head *page_list,
-                                     struct zone *zone,
+                                     struct pglist_data *pgdat,
                                      struct scan_control *sc,
                                      enum ttu_flags ttu_flags,
                                      unsigned long *ret_nr_dirty,
@@ -917,7 +938,6 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                        goto keep;
 
                VM_BUG_ON_PAGE(PageActive(page), page);
-               VM_BUG_ON_PAGE(page_zone(page) != zone, page);
 
                sc->nr_scanned++;
 
@@ -996,7 +1016,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                        /* Case 1 above */
                        if (current_is_kswapd() &&
                            PageReclaim(page) &&
-                           test_bit(ZONE_WRITEBACK, &zone->flags)) {
+                           test_bit(PGDAT_WRITEBACK, &pgdat->flags)) {
                                nr_immediate++;
                                goto keep_locked;
 
@@ -1092,14 +1112,14 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                         */
                        if (page_is_file_cache(page) &&
                                        (!current_is_kswapd() ||
-                                        !test_bit(ZONE_DIRTY, &zone->flags))) {
+                                        !test_bit(PGDAT_DIRTY, &pgdat->flags))) {
                                /*
                                 * Immediately reclaim when written back.
                                 * Similar in principal to deactivate_page()
                                 * except we already have the page isolated
                                 * and know it's dirty
                                 */
-                               inc_zone_page_state(page, NR_VMSCAN_IMMEDIATE);
+                               inc_node_page_state(page, NR_VMSCAN_IMMEDIATE);
                                SetPageReclaim(page);
 
                                goto keep_locked;
@@ -1266,11 +1286,11 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone,
                }
        }
 
-       ret = shrink_page_list(&clean_pages, zone, &sc,
+       ret = shrink_page_list(&clean_pages, zone->zone_pgdat, &sc,
                        TTU_UNMAP|TTU_IGNORE_ACCESS,
                        &dummy1, &dummy2, &dummy3, &dummy4, &dummy5, true);
        list_splice(&clean_pages, page_list);
-       mod_zone_page_state(zone, NR_ISOLATED_FILE, -ret);
+       mod_node_page_state(zone->zone_pgdat, NR_ISOLATED_FILE, -ret);
        return ret;
 }
 
@@ -1348,8 +1368,31 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode)
        return ret;
 }
 
+
 /*
- * zone->lru_lock is heavily contended.  Some of the functions that
+ * Update LRU sizes after isolating pages. The LRU size updates must
+ * be complete before mem_cgroup_update_lru_size due to a santity check.
+ */
+static __always_inline void update_lru_sizes(struct lruvec *lruvec,
+                       enum lru_list lru, unsigned long *nr_zone_taken,
+                       unsigned long nr_taken)
+{
+       int zid;
+
+       for (zid = 0; zid < MAX_NR_ZONES; zid++) {
+               if (!nr_zone_taken[zid])
+                       continue;
+
+               __update_lru_size(lruvec, lru, zid, -nr_zone_taken[zid]);
+       }
+
+#ifdef CONFIG_MEMCG
+       mem_cgroup_update_lru_size(lruvec, lru, -nr_taken);
+#endif
+}
+
+/*
+ * zone_lru_lock is heavily contended.  Some of the functions that
  * shrink the lists perform better by taking out a batch of pages
  * and working on them outside the LRU lock.
  *
@@ -1375,10 +1418,13 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
 {
        struct list_head *src = &lruvec->lists[lru];
        unsigned long nr_taken = 0;
-       unsigned long scan;
+       unsigned long nr_zone_taken[MAX_NR_ZONES] = { 0 };
+       unsigned long nr_skipped[MAX_NR_ZONES] = { 0, };
+       unsigned long scan, nr_pages;
+       LIST_HEAD(pages_skipped);
 
        for (scan = 0; scan < nr_to_scan && nr_taken < nr_to_scan &&
-                                       !list_empty(src); scan++) {
+                                       !list_empty(src);) {
                struct page *page;
 
                page = lru_to_page(src);
@@ -1386,9 +1432,23 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
 
                VM_BUG_ON_PAGE(!PageLRU(page), page);
 
+               if (page_zonenum(page) > sc->reclaim_idx) {
+                       list_move(&page->lru, &pages_skipped);
+                       nr_skipped[page_zonenum(page)]++;
+                       continue;
+               }
+
+               /*
+                * Account for scanned and skipped separetly to avoid the pgdat
+                * being prematurely marked unreclaimable by pgdat_reclaimable.
+                */
+               scan++;
+
                switch (__isolate_lru_page(page, mode)) {
                case 0:
-                       nr_taken += hpage_nr_pages(page);
+                       nr_pages = hpage_nr_pages(page);
+                       nr_taken += nr_pages;
+                       nr_zone_taken[page_zonenum(page)] += nr_pages;
                        list_move(&page->lru, dst);
                        break;
 
@@ -1402,9 +1462,38 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
                }
        }
 
+       /*
+        * Splice any skipped pages to the start of the LRU list. Note that
+        * this disrupts the LRU order when reclaiming for lower zones but
+        * we cannot splice to the tail. If we did then the SWAP_CLUSTER_MAX
+        * scanning would soon rescan the same pages to skip and put the
+        * system at risk of premature OOM.
+        */
+       if (!list_empty(&pages_skipped)) {
+               int zid;
+               unsigned long total_skipped = 0;
+
+               for (zid = 0; zid < MAX_NR_ZONES; zid++) {
+                       if (!nr_skipped[zid])
+                               continue;
+
+                       __count_zid_vm_events(PGSCAN_SKIP, zid, nr_skipped[zid]);
+                       total_skipped += nr_skipped[zid];
+               }
+
+               /*
+                * Account skipped pages as a partial scan as the pgdat may be
+                * close to unreclaimable. If the LRU list is empty, account
+                * skipped pages as a full scan.
+                */
+               scan += list_empty(src) ? total_skipped : total_skipped >> 2;
+
+               list_splice(&pages_skipped, src);
+       }
        *nr_scanned = scan;
-       trace_mm_vmscan_lru_isolate(sc->order, nr_to_scan, scan,
+       trace_mm_vmscan_lru_isolate(sc->reclaim_idx, sc->order, nr_to_scan, scan,
                                    nr_taken, mode, is_file_lru(lru));
+       update_lru_sizes(lruvec, lru, nr_zone_taken, nr_taken);
        return nr_taken;
 }
 
@@ -1444,8 +1533,8 @@ int isolate_lru_page(struct page *page)
                struct zone *zone = page_zone(page);
                struct lruvec *lruvec;
 
-               spin_lock_irq(&zone->lru_lock);
-               lruvec = mem_cgroup_page_lruvec(page, zone);
+               spin_lock_irq(zone_lru_lock(zone));
+               lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat);
                if (PageLRU(page)) {
                        int lru = page_lru(page);
                        get_page(page);
@@ -1453,7 +1542,7 @@ int isolate_lru_page(struct page *page)
                        del_page_from_lru_list(page, lruvec, lru);
                        ret = 0;
                }
-               spin_unlock_irq(&zone->lru_lock);
+               spin_unlock_irq(zone_lru_lock(zone));
        }
        return ret;
 }
@@ -1465,7 +1554,7 @@ int isolate_lru_page(struct page *page)
  * the LRU list will go small and be scanned faster than necessary, leading to
  * unnecessary swapping, thrashing and OOM.
  */
-static int too_many_isolated(struct zone *zone, int file,
+static int too_many_isolated(struct pglist_data *pgdat, int file,
                struct scan_control *sc)
 {
        unsigned long inactive, isolated;
@@ -1477,11 +1566,11 @@ static int too_many_isolated(struct zone *zone, int file,
                return 0;
 
        if (file) {
-               inactive = zone_page_state(zone, NR_INACTIVE_FILE);
-               isolated = zone_page_state(zone, NR_ISOLATED_FILE);
+               inactive = node_page_state(pgdat, NR_INACTIVE_FILE);
+               isolated = node_page_state(pgdat, NR_ISOLATED_FILE);
        } else {
-               inactive = zone_page_state(zone, NR_INACTIVE_ANON);
-               isolated = zone_page_state(zone, NR_ISOLATED_ANON);
+               inactive = node_page_state(pgdat, NR_INACTIVE_ANON);
+               isolated = node_page_state(pgdat, NR_ISOLATED_ANON);
        }
 
        /*
@@ -1499,7 +1588,7 @@ static noinline_for_stack void
 putback_inactive_pages(struct lruvec *lruvec, struct list_head *page_list)
 {
        struct zone_reclaim_stat *reclaim_stat = &lruvec->reclaim_stat;
-       struct zone *zone = lruvec_zone(lruvec);
+       struct pglist_data *pgdat = lruvec_pgdat(lruvec);
        LIST_HEAD(pages_to_free);
 
        /*
@@ -1512,13 +1601,13 @@ putback_inactive_pages(struct lruvec *lruvec, struct list_head *page_list)
                VM_BUG_ON_PAGE(PageLRU(page), page);
                list_del(&page->lru);
                if (unlikely(!page_evictable(page))) {
-                       spin_unlock_irq(&zone->lru_lock);
+                       spin_unlock_irq(&pgdat->lru_lock);
                        putback_lru_page(page);
-                       spin_lock_irq(&zone->lru_lock);
+                       spin_lock_irq(&pgdat->lru_lock);
                        continue;
                }
 
-               lruvec = mem_cgroup_page_lruvec(page, zone);
+               lruvec = mem_cgroup_page_lruvec(page, pgdat);
 
                SetPageLRU(page);
                lru = page_lru(page);
@@ -1535,10 +1624,10 @@ putback_inactive_pages(struct lruvec *lruvec, struct list_head *page_list)
                        del_page_from_lru_list(page, lruvec, lru);
 
                        if (unlikely(PageCompound(page))) {
-                               spin_unlock_irq(&zone->lru_lock);
+                               spin_unlock_irq(&pgdat->lru_lock);
                                mem_cgroup_uncharge(page);
                                (*get_compound_page_dtor(page))(page);
-                               spin_lock_irq(&zone->lru_lock);
+                               spin_lock_irq(&pgdat->lru_lock);
                        } else
                                list_add(&page->lru, &pages_to_free);
                }
@@ -1563,8 +1652,32 @@ static int current_may_throttle(void)
                bdi_write_congested(current->backing_dev_info);
 }
 
+static bool inactive_reclaimable_pages(struct lruvec *lruvec,
+                               struct scan_control *sc, enum lru_list lru)
+{
+       int zid;
+       struct zone *zone;
+       int file = is_file_lru(lru);
+       struct pglist_data *pgdat = lruvec_pgdat(lruvec);
+
+       if (!global_reclaim(sc))
+               return true;
+
+       for (zid = sc->reclaim_idx; zid >= 0; zid--) {
+               zone = &pgdat->node_zones[zid];
+               if (!populated_zone(zone))
+                       continue;
+
+               if (zone_page_state_snapshot(zone, NR_ZONE_LRU_BASE +
+                               LRU_FILE * file) >= SWAP_CLUSTER_MAX)
+                       return true;
+       }
+
+       return false;
+}
+
 /*
- * shrink_inactive_list() is a helper for shrink_zone().  It returns the number
+ * shrink_inactive_list() is a helper for shrink_node().  It returns the number
  * of reclaimed pages
  */
 static noinline_for_stack unsigned long
@@ -1582,10 +1695,13 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
        unsigned long nr_immediate = 0;
        isolate_mode_t isolate_mode = 0;
        int file = is_file_lru(lru);
-       struct zone *zone = lruvec_zone(lruvec);
+       struct pglist_data *pgdat = lruvec_pgdat(lruvec);
        struct zone_reclaim_stat *reclaim_stat = &lruvec->reclaim_stat;
 
-       while (unlikely(too_many_isolated(zone, file, sc))) {
+       if (!inactive_reclaimable_pages(lruvec, sc, lru))
+               return 0;
+
+       while (unlikely(too_many_isolated(pgdat, file, sc))) {
                congestion_wait(BLK_RW_ASYNC, HZ/10);
 
                /* We are about to die and free our memory. Return now. */
@@ -1600,48 +1716,45 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
        if (!sc->may_writepage)
                isolate_mode |= ISOLATE_CLEAN;
 
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irq(&pgdat->lru_lock);
 
        nr_taken = isolate_lru_pages(nr_to_scan, lruvec, &page_list,
                                     &nr_scanned, sc, isolate_mode, lru);
 
-       update_lru_size(lruvec, lru, -nr_taken);
-       __mod_zone_page_state(zone, NR_ISOLATED_ANON + file, nr_taken);
+       __mod_node_page_state(pgdat, NR_ISOLATED_ANON + file, nr_taken);
        reclaim_stat->recent_scanned[file] += nr_taken;
 
        if (global_reclaim(sc)) {
-               __mod_zone_page_state(zone, NR_PAGES_SCANNED, nr_scanned);
+               __mod_node_page_state(pgdat, NR_PAGES_SCANNED, nr_scanned);
                if (current_is_kswapd())
-                       __count_zone_vm_events(PGSCAN_KSWAPD, zone, nr_scanned);
+                       __count_vm_events(PGSCAN_KSWAPD, nr_scanned);
                else
-                       __count_zone_vm_events(PGSCAN_DIRECT, zone, nr_scanned);
+                       __count_vm_events(PGSCAN_DIRECT, nr_scanned);
        }
-       spin_unlock_irq(&zone->lru_lock);
+       spin_unlock_irq(&pgdat->lru_lock);
 
        if (nr_taken == 0)
                return 0;
 
-       nr_reclaimed = shrink_page_list(&page_list, zone, sc, TTU_UNMAP,
+       nr_reclaimed = shrink_page_list(&page_list, pgdat, sc, TTU_UNMAP,
                                &nr_dirty, &nr_unqueued_dirty, &nr_congested,
                                &nr_writeback, &nr_immediate,
                                false);
 
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irq(&pgdat->lru_lock);
 
        if (global_reclaim(sc)) {
                if (current_is_kswapd())
-                       __count_zone_vm_events(PGSTEAL_KSWAPD, zone,
-                                              nr_reclaimed);
+                       __count_vm_events(PGSTEAL_KSWAPD, nr_reclaimed);
                else
-                       __count_zone_vm_events(PGSTEAL_DIRECT, zone,
-                                              nr_reclaimed);
+                       __count_vm_events(PGSTEAL_DIRECT, nr_reclaimed);
        }
 
        putback_inactive_pages(lruvec, &page_list);
 
-       __mod_zone_page_state(zone, NR_ISOLATED_ANON + file, -nr_taken);
+       __mod_node_page_state(pgdat, NR_ISOLATED_ANON + file, -nr_taken);
 
-       spin_unlock_irq(&zone->lru_lock);
+       spin_unlock_irq(&pgdat->lru_lock);
 
        mem_cgroup_uncharge_list(&page_list);
        free_hot_cold_page_list(&page_list, true);
@@ -1661,7 +1774,7 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
         * are encountered in the nr_immediate check below.
         */
        if (nr_writeback && nr_writeback == nr_taken)
-               set_bit(ZONE_WRITEBACK, &zone->flags);
+               set_bit(PGDAT_WRITEBACK, &pgdat->flags);
 
        /*
         * Legacy memcg will stall in page writeback so avoid forcibly
@@ -1673,16 +1786,16 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
                 * backed by a congested BDI and wait_iff_congested will stall.
                 */
                if (nr_dirty && nr_dirty == nr_congested)
-                       set_bit(ZONE_CONGESTED, &zone->flags);
+                       set_bit(PGDAT_CONGESTED, &pgdat->flags);
 
                /*
                 * If dirty pages are scanned that are not queued for IO, it
                 * implies that flushers are not keeping up. In this case, flag
-                * the zone ZONE_DIRTY and kswapd will start writing pages from
+                * the pgdat PGDAT_DIRTY and kswapd will start writing pages from
                 * reclaim context.
                 */
                if (nr_unqueued_dirty == nr_taken)
-                       set_bit(ZONE_DIRTY, &zone->flags);
+                       set_bit(PGDAT_DIRTY, &pgdat->flags);
 
                /*
                 * If kswapd scans pages marked marked for immediate
@@ -1701,9 +1814,10 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
         */
        if (!sc->hibernation_mode && !current_is_kswapd() &&
            current_may_throttle())
-               wait_iff_congested(zone, BLK_RW_ASYNC, HZ/10);
+               wait_iff_congested(pgdat, BLK_RW_ASYNC, HZ/10);
 
-       trace_mm_vmscan_lru_shrink_inactive(zone, nr_scanned, nr_reclaimed,
+       trace_mm_vmscan_lru_shrink_inactive(pgdat->node_id,
+                       nr_scanned, nr_reclaimed,
                        sc->priority, file);
        return nr_reclaimed;
 }
@@ -1715,9 +1829,9 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
  * processes, from rmap.
  *
  * If the pages are mostly unmapped, the processing is fast and it is
- * appropriate to hold zone->lru_lock across the whole operation.  But if
+ * appropriate to hold zone_lru_lock across the whole operation.  But if
  * the pages are mapped, the processing is slow (page_referenced()) so we
- * should drop zone->lru_lock around each page.  It's impossible to balance
+ * should drop zone_lru_lock around each page.  It's impossible to balance
  * this, so instead we remove the pages from the LRU while processing them.
  * It is safe to rely on PG_active against the non-LRU pages in here because
  * nobody will play with that bit on a non-LRU page.
@@ -1731,20 +1845,20 @@ static void move_active_pages_to_lru(struct lruvec *lruvec,
                                     struct list_head *pages_to_free,
                                     enum lru_list lru)
 {
-       struct zone *zone = lruvec_zone(lruvec);
+       struct pglist_data *pgdat = lruvec_pgdat(lruvec);
        unsigned long pgmoved = 0;
        struct page *page;
        int nr_pages;
 
        while (!list_empty(list)) {
                page = lru_to_page(list);
-               lruvec = mem_cgroup_page_lruvec(page, zone);
+               lruvec = mem_cgroup_page_lruvec(page, pgdat);
 
                VM_BUG_ON_PAGE(PageLRU(page), page);
                SetPageLRU(page);
 
                nr_pages = hpage_nr_pages(page);
-               update_lru_size(lruvec, lru, nr_pages);
+               update_lru_size(lruvec, lru, page_zonenum(page), nr_pages);
                list_move(&page->lru, &lruvec->lists[lru]);
                pgmoved += nr_pages;
 
@@ -1754,10 +1868,10 @@ static void move_active_pages_to_lru(struct lruvec *lruvec,
                        del_page_from_lru_list(page, lruvec, lru);
 
                        if (unlikely(PageCompound(page))) {
-                               spin_unlock_irq(&zone->lru_lock);
+                               spin_unlock_irq(&pgdat->lru_lock);
                                mem_cgroup_uncharge(page);
                                (*get_compound_page_dtor(page))(page);
-                               spin_lock_irq(&zone->lru_lock);
+                               spin_lock_irq(&pgdat->lru_lock);
                        } else
                                list_add(&page->lru, pages_to_free);
                }
@@ -1783,7 +1897,7 @@ static void shrink_active_list(unsigned long nr_to_scan,
        unsigned long nr_rotated = 0;
        isolate_mode_t isolate_mode = 0;
        int file = is_file_lru(lru);
-       struct zone *zone = lruvec_zone(lruvec);
+       struct pglist_data *pgdat = lruvec_pgdat(lruvec);
 
        lru_add_drain();
 
@@ -1792,20 +1906,19 @@ static void shrink_active_list(unsigned long nr_to_scan,
        if (!sc->may_writepage)
                isolate_mode |= ISOLATE_CLEAN;
 
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irq(&pgdat->lru_lock);
 
        nr_taken = isolate_lru_pages(nr_to_scan, lruvec, &l_hold,
                                     &nr_scanned, sc, isolate_mode, lru);
 
-       update_lru_size(lruvec, lru, -nr_taken);
-       __mod_zone_page_state(zone, NR_ISOLATED_ANON + file, nr_taken);
+       __mod_node_page_state(pgdat, NR_ISOLATED_ANON + file, nr_taken);
        reclaim_stat->recent_scanned[file] += nr_taken;
 
        if (global_reclaim(sc))
-               __mod_zone_page_state(zone, NR_PAGES_SCANNED, nr_scanned);
-       __count_zone_vm_events(PGREFILL, zone, nr_scanned);
+               __mod_node_page_state(pgdat, NR_PAGES_SCANNED, nr_scanned);
+       __count_vm_events(PGREFILL, nr_scanned);
 
-       spin_unlock_irq(&zone->lru_lock);
+       spin_unlock_irq(&pgdat->lru_lock);
 
        while (!list_empty(&l_hold)) {
                cond_resched();
@@ -1850,7 +1963,7 @@ static void shrink_active_list(unsigned long nr_to_scan,
        /*
         * Move pages back to the lru list.
         */
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irq(&pgdat->lru_lock);
        /*
         * Count referenced pages from currently used mappings as rotated,
         * even though only some of them are actually re-activated.  This
@@ -1861,8 +1974,8 @@ static void shrink_active_list(unsigned long nr_to_scan,
 
        move_active_pages_to_lru(lruvec, &l_active, &l_hold, lru);
        move_active_pages_to_lru(lruvec, &l_inactive, &l_hold, lru - LRU_ACTIVE);
-       __mod_zone_page_state(zone, NR_ISOLATED_ANON + file, -nr_taken);
-       spin_unlock_irq(&zone->lru_lock);
+       __mod_node_page_state(pgdat, NR_ISOLATED_ANON + file, -nr_taken);
+       spin_unlock_irq(&pgdat->lru_lock);
 
        mem_cgroup_uncharge_list(&l_hold);
        free_hot_cold_page_list(&l_hold, true);
@@ -1894,12 +2007,15 @@ static void shrink_active_list(unsigned long nr_to_scan,
  *    1TB     101        10GB
  *   10TB     320        32GB
  */
-static bool inactive_list_is_low(struct lruvec *lruvec, bool file)
+static bool inactive_list_is_low(struct lruvec *lruvec, bool file,
+                                               struct scan_control *sc)
 {
        unsigned long inactive_ratio;
        unsigned long inactive;
        unsigned long active;
        unsigned long gb;
+       struct pglist_data *pgdat = lruvec_pgdat(lruvec);
+       int zid;
 
        /*
         * If we don't have swap space, anonymous page deactivation
@@ -1911,6 +2027,27 @@ static bool inactive_list_is_low(struct lruvec *lruvec, bool file)
        inactive = lruvec_lru_size(lruvec, file * LRU_FILE);
        active = lruvec_lru_size(lruvec, file * LRU_FILE + LRU_ACTIVE);
 
+       /*
+        * For zone-constrained allocations, it is necessary to check if
+        * deactivations are required for lowmem to be reclaimed. This
+        * calculates the inactive/active pages available in eligible zones.
+        */
+       for (zid = sc->reclaim_idx + 1; zid < MAX_NR_ZONES; zid++) {
+               struct zone *zone = &pgdat->node_zones[zid];
+               unsigned long inactive_zone, active_zone;
+
+               if (!populated_zone(zone))
+                       continue;
+
+               inactive_zone = zone_page_state(zone,
+                               NR_ZONE_LRU_BASE + (file * LRU_FILE));
+               active_zone = zone_page_state(zone,
+                               NR_ZONE_LRU_BASE + (file * LRU_FILE) + LRU_ACTIVE);
+
+               inactive -= min(inactive, inactive_zone);
+               active -= min(active, active_zone);
+       }
+
        gb = (inactive + active) >> (30 - PAGE_SHIFT);
        if (gb)
                inactive_ratio = int_sqrt(10 * gb);
@@ -1924,7 +2061,7 @@ static unsigned long shrink_list(enum lru_list lru, unsigned long nr_to_scan,
                                 struct lruvec *lruvec, struct scan_control *sc)
 {
        if (is_active_lru(lru)) {
-               if (inactive_list_is_low(lruvec, is_file_lru(lru)))
+               if (inactive_list_is_low(lruvec, is_file_lru(lru), sc))
                        shrink_active_list(nr_to_scan, lruvec, sc, lru);
                return 0;
        }
@@ -1956,7 +2093,7 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,
        struct zone_reclaim_stat *reclaim_stat = &lruvec->reclaim_stat;
        u64 fraction[2];
        u64 denominator = 0;    /* gcc */
-       struct zone *zone = lruvec_zone(lruvec);
+       struct pglist_data *pgdat = lruvec_pgdat(lruvec);
        unsigned long anon_prio, file_prio;
        enum scan_balance scan_balance;
        unsigned long anon, file;
@@ -1977,7 +2114,7 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,
         * well.
         */
        if (current_is_kswapd()) {
-               if (!zone_reclaimable(zone))
+               if (!pgdat_reclaimable(pgdat))
                        force_scan = true;
                if (!mem_cgroup_online(memcg))
                        force_scan = true;
@@ -2023,14 +2160,24 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,
         * anon pages.  Try to detect this based on file LRU size.
         */
        if (global_reclaim(sc)) {
-               unsigned long zonefile;
-               unsigned long zonefree;
+               unsigned long pgdatfile;
+               unsigned long pgdatfree;
+               int z;
+               unsigned long total_high_wmark = 0;
 
-               zonefree = zone_page_state(zone, NR_FREE_PAGES);
-               zonefile = zone_page_state(zone, NR_ACTIVE_FILE) +
-                          zone_page_state(zone, NR_INACTIVE_FILE);
+               pgdatfree = sum_zone_node_page_state(pgdat->node_id, NR_FREE_PAGES);
+               pgdatfile = node_page_state(pgdat, NR_ACTIVE_FILE) +
+                          node_page_state(pgdat, NR_INACTIVE_FILE);
 
-               if (unlikely(zonefile + zonefree <= high_wmark_pages(zone))) {
+               for (z = 0; z < MAX_NR_ZONES; z++) {
+                       struct zone *zone = &pgdat->node_zones[z];
+                       if (!populated_zone(zone))
+                               continue;
+
+                       total_high_wmark += high_wmark_pages(zone);
+               }
+
+               if (unlikely(pgdatfile + pgdatfree <= total_high_wmark)) {
                        scan_balance = SCAN_ANON;
                        goto out;
                }
@@ -2045,7 +2192,7 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,
         * lruvec even if it has plenty of old anonymous pages unless the
         * system is under heavy pressure.
         */
-       if (!inactive_list_is_low(lruvec, true) &&
+       if (!inactive_list_is_low(lruvec, true, sc) &&
            lruvec_lru_size(lruvec, LRU_INACTIVE_FILE) >> sc->priority) {
                scan_balance = SCAN_FILE;
                goto out;
@@ -2077,7 +2224,7 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,
        file  = lruvec_lru_size(lruvec, LRU_ACTIVE_FILE) +
                lruvec_lru_size(lruvec, LRU_INACTIVE_FILE);
 
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irq(&pgdat->lru_lock);
        if (unlikely(reclaim_stat->recent_scanned[0] > anon / 4)) {
                reclaim_stat->recent_scanned[0] /= 2;
                reclaim_stat->recent_rotated[0] /= 2;
@@ -2098,7 +2245,7 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,
 
        fp = file_prio * (reclaim_stat->recent_scanned[1] + 1);
        fp /= reclaim_stat->recent_rotated[1] + 1;
-       spin_unlock_irq(&zone->lru_lock);
+       spin_unlock_irq(&pgdat->lru_lock);
 
        fraction[0] = ap;
        fraction[1] = fp;
@@ -2174,12 +2321,12 @@ static inline void init_tlb_ubc(void)
 #endif /* CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH */
 
 /*
- * This is a basic per-zone page freer.  Used by both kswapd and direct reclaim.
+ * This is a basic per-node page freer.  Used by both kswapd and direct reclaim.
  */
-static void shrink_zone_memcg(struct zone *zone, struct mem_cgroup *memcg,
+static void shrink_node_memcg(struct pglist_data *pgdat, struct mem_cgroup *memcg,
                              struct scan_control *sc, unsigned long *lru_pages)
 {
-       struct lruvec *lruvec = mem_cgroup_zone_lruvec(zone, memcg);
+       struct lruvec *lruvec = mem_cgroup_lruvec(pgdat, memcg);
        unsigned long nr[NR_LRU_LISTS];
        unsigned long targets[NR_LRU_LISTS];
        unsigned long nr_to_scan;
@@ -2287,7 +2434,7 @@ static void shrink_zone_memcg(struct zone *zone, struct mem_cgroup *memcg,
         * Even if we did not try to evict anon pages at all, we want to
         * rebalance the anon lru active/inactive ratio.
         */
-       if (inactive_list_is_low(lruvec, false))
+       if (inactive_list_is_low(lruvec, false, sc))
                shrink_active_list(SWAP_CLUSTER_MAX, lruvec,
                                   sc, LRU_ACTIVE_ANON);
 
@@ -2312,13 +2459,14 @@ static bool in_reclaim_compaction(struct scan_control *sc)
  * calls try_to_compact_zone() that it will have enough free pages to succeed.
  * It will give up earlier than that if there is difficulty reclaiming pages.
  */
-static inline bool should_continue_reclaim(struct zone *zone,
+static inline bool should_continue_reclaim(struct pglist_data *pgdat,
                                        unsigned long nr_reclaimed,
                                        unsigned long nr_scanned,
                                        struct scan_control *sc)
 {
        unsigned long pages_for_compaction;
        unsigned long inactive_lru_pages;
+       int z;
 
        /* If not in reclaim/compaction mode, stop */
        if (!in_reclaim_compaction(sc))
@@ -2352,25 +2500,32 @@ static inline bool should_continue_reclaim(struct zone *zone,
         * inactive lists are large enough, continue reclaiming
         */
        pages_for_compaction = (2UL << sc->order);
-       inactive_lru_pages = zone_page_state(zone, NR_INACTIVE_FILE);
+       inactive_lru_pages = node_page_state(pgdat, NR_INACTIVE_FILE);
        if (get_nr_swap_pages() > 0)
-               inactive_lru_pages += zone_page_state(zone, NR_INACTIVE_ANON);
+               inactive_lru_pages += node_page_state(pgdat, NR_INACTIVE_ANON);
        if (sc->nr_reclaimed < pages_for_compaction &&
                        inactive_lru_pages > pages_for_compaction)
                return true;
 
        /* If compaction would go ahead or the allocation would succeed, stop */
-       switch (compaction_suitable(zone, sc->order, 0, 0)) {
-       case COMPACT_PARTIAL:
-       case COMPACT_CONTINUE:
-               return false;
-       default:
-               return true;
+       for (z = 0; z <= sc->reclaim_idx; z++) {
+               struct zone *zone = &pgdat->node_zones[z];
+               if (!populated_zone(zone))
+                       continue;
+
+               switch (compaction_suitable(zone, sc->order, 0, sc->reclaim_idx)) {
+               case COMPACT_PARTIAL:
+               case COMPACT_CONTINUE:
+                       return false;
+               default:
+                       /* check next zone */
+                       ;
+               }
        }
+       return true;
 }
 
-static bool shrink_zone(struct zone *zone, struct scan_control *sc,
-                       bool is_classzone)
+static bool shrink_node(pg_data_t *pgdat, struct scan_control *sc)
 {
        struct reclaim_state *reclaim_state = current->reclaim_state;
        unsigned long nr_reclaimed, nr_scanned;
@@ -2379,10 +2534,10 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
        do {
                struct mem_cgroup *root = sc->target_mem_cgroup;
                struct mem_cgroup_reclaim_cookie reclaim = {
-                       .zone = zone,
+                       .pgdat = pgdat,
                        .priority = sc->priority,
                };
-               unsigned long zone_lru_pages = 0;
+               unsigned long node_lru_pages = 0;
                struct mem_cgroup *memcg;
 
                nr_reclaimed = sc->nr_reclaimed;
@@ -2403,11 +2558,11 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
                        reclaimed = sc->nr_reclaimed;
                        scanned = sc->nr_scanned;
 
-                       shrink_zone_memcg(zone, memcg, sc, &lru_pages);
-                       zone_lru_pages += lru_pages;
+                       shrink_node_memcg(pgdat, memcg, sc, &lru_pages);
+                       node_lru_pages += lru_pages;
 
-                       if (memcg && is_classzone)
-                               shrink_slab(sc->gfp_mask, zone_to_nid(zone),
+                       if (!global_reclaim(sc))
+                               shrink_slab(sc->gfp_mask, pgdat->node_id,
                                            memcg, sc->nr_scanned - scanned,
                                            lru_pages);
 
@@ -2419,7 +2574,7 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
                        /*
                         * Direct reclaim and kswapd have to scan all memory
                         * cgroups to fulfill the overall scan target for the
-                        * zone.
+                        * node.
                         *
                         * Limit reclaim, on the other hand, only cares about
                         * nr_to_reclaim pages to be reclaimed and it will
@@ -2437,10 +2592,10 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
                 * Shrink the slab caches in the same proportion that
                 * the eligible LRU pages were scanned.
                 */
-               if (global_reclaim(sc) && is_classzone)
-                       shrink_slab(sc->gfp_mask, zone_to_nid(zone), NULL,
+               if (global_reclaim(sc))
+                       shrink_slab(sc->gfp_mask, pgdat->node_id, NULL,
                                    sc->nr_scanned - nr_scanned,
-                                   zone_lru_pages);
+                                   node_lru_pages);
 
                if (reclaim_state) {
                        sc->nr_reclaimed += reclaim_state->reclaimed_slab;
@@ -2455,7 +2610,7 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
                if (sc->nr_reclaimed - nr_reclaimed)
                        reclaimable = true;
 
-       } while (should_continue_reclaim(zone, sc->nr_reclaimed - nr_reclaimed,
+       } while (should_continue_reclaim(pgdat, sc->nr_reclaimed - nr_reclaimed,
                                         sc->nr_scanned - nr_scanned, sc));
 
        return reclaimable;
@@ -2465,9 +2620,9 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
  * Returns true if compaction should go ahead for a high-order request, or
  * the high-order allocation would succeed without compaction.
  */
-static inline bool compaction_ready(struct zone *zone, int order, int classzone_idx)
+static inline bool compaction_ready(struct zone *zone, struct scan_control *sc)
 {
-       unsigned long balance_gap, watermark;
+       unsigned long watermark;
        bool watermark_ok;
 
        /*
@@ -2476,23 +2631,21 @@ static inline bool compaction_ready(struct zone *zone, int order, int classzone_
         * there is a buffer of free pages available to give compaction
         * a reasonable chance of completing and allocating the page
         */
-       balance_gap = min(low_wmark_pages(zone), DIV_ROUND_UP(
-                       zone->managed_pages, KSWAPD_ZONE_BALANCE_GAP_RATIO));
-       watermark = high_wmark_pages(zone) + balance_gap + (2UL << order);
-       watermark_ok = zone_watermark_ok_safe(zone, 0, watermark, classzone_idx);
+       watermark = high_wmark_pages(zone) + (2UL << sc->order);
+       watermark_ok = zone_watermark_ok_safe(zone, 0, watermark, sc->reclaim_idx);
 
        /*
         * If compaction is deferred, reclaim up to a point where
         * compaction will have a chance of success when re-enabled
         */
-       if (compaction_deferred(zone, order))
+       if (compaction_deferred(zone, sc->order))
                return watermark_ok;
 
        /*
         * If compaction is not ready to start and allocation is not likely
         * to succeed without it, then keep reclaiming.
         */
-       if (compaction_suitable(zone, order, 0, classzone_idx) == COMPACT_SKIPPED)
+       if (compaction_suitable(zone, sc->order, 0, sc->reclaim_idx) == COMPACT_SKIPPED)
                return false;
 
        return watermark_ok;
@@ -2503,14 +2656,6 @@ static inline bool compaction_ready(struct zone *zone, int order, int classzone_
  * try to reclaim pages from zones which will satisfy the caller's allocation
  * request.
  *
- * We reclaim from a zone even if that zone is over high_wmark_pages(zone).
- * Because:
- * a) The caller may be trying to free *extra* pages to satisfy a higher-order
- *    allocation or
- * b) The target zone may be at high_wmark_pages(zone) but the lower zones
- *    must go *over* high_wmark_pages(zone) to satisfy the `incremental min'
- *    zone defense algorithm.
- *
  * If a zone is deemed to be full of pinned pages then just give it a light
  * scan then give up on it.
  */
@@ -2521,7 +2666,7 @@ static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
        unsigned long nr_soft_reclaimed;
        unsigned long nr_soft_scanned;
        gfp_t orig_mask;
-       enum zone_type requested_highidx = gfp_zone(sc->gfp_mask);
+       pg_data_t *last_pgdat = NULL;
 
        /*
         * If the number of buffer_heads in the machine exceeds the maximum
@@ -2529,21 +2674,13 @@ static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
         * highmem pages could be pinning lowmem pages storing buffer_heads
         */
        orig_mask = sc->gfp_mask;
-       if (buffer_heads_over_limit)
+       if (buffer_heads_over_limit) {
                sc->gfp_mask |= __GFP_HIGHMEM;
+               sc->reclaim_idx = gfp_zone(sc->gfp_mask);
+       }
 
        for_each_zone_zonelist_nodemask(zone, z, zonelist,
-                                       gfp_zone(sc->gfp_mask), sc->nodemask) {
-               enum zone_type classzone_idx;
-
-               if (!populated_zone(zone))
-                       continue;
-
-               classzone_idx = requested_highidx;
-               while (!populated_zone(zone->zone_pgdat->node_zones +
-                                                       classzone_idx))
-                       classzone_idx--;
-
+                                       sc->reclaim_idx, sc->nodemask) {
                /*
                 * Take care memory controller reclaiming has small influence
                 * to global LRU.
@@ -2554,7 +2691,7 @@ static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
                                continue;
 
                        if (sc->priority != DEF_PRIORITY &&
-                           !zone_reclaimable(zone))
+                           !pgdat_reclaimable(zone->zone_pgdat))
                                continue;       /* Let kswapd poll it */
 
                        /*
@@ -2568,12 +2705,20 @@ static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
                         */
                        if (IS_ENABLED(CONFIG_COMPACTION) &&
                            sc->order > PAGE_ALLOC_COSTLY_ORDER &&
-                           zonelist_zone_idx(z) <= requested_highidx &&
-                           compaction_ready(zone, sc->order, requested_highidx)) {
+                           compaction_ready(zone, sc)) {
                                sc->compaction_ready = true;
                                continue;
                        }
 
+                       /*
+                        * Shrink each node in the zonelist once. If the
+                        * zonelist is ordered by zone (not the default) then a
+                        * node may be shrunk multiple times but in that case
+                        * the user prefers lower zones being preserved.
+                        */
+                       if (zone->zone_pgdat == last_pgdat)
+                               continue;
+
                        /*
                         * This steals pages from memory cgroups over softlimit
                         * and returns the number of reclaimed pages and
@@ -2581,7 +2726,7 @@ static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
                         * and balancing, not for a memcg's limit.
                         */
                        nr_soft_scanned = 0;
-                       nr_soft_reclaimed = mem_cgroup_soft_limit_reclaim(zone,
+                       nr_soft_reclaimed = mem_cgroup_soft_limit_reclaim(zone->zone_pgdat,
                                                sc->order, sc->gfp_mask,
                                                &nr_soft_scanned);
                        sc->nr_reclaimed += nr_soft_reclaimed;
@@ -2589,7 +2734,11 @@ static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
                        /* need some check for avoid more shrink_zone() */
                }
 
-               shrink_zone(zone, sc, zone_idx(zone) == classzone_idx);
+               /* See comment about same check for global reclaim above */
+               if (zone->zone_pgdat == last_pgdat)
+                       continue;
+               last_pgdat = zone->zone_pgdat;
+               shrink_node(zone->zone_pgdat, sc);
        }
 
        /*
@@ -2625,7 +2774,7 @@ retry:
        delayacct_freepages_start();
 
        if (global_reclaim(sc))
-               count_vm_event(ALLOCSTALL);
+               __count_zid_vm_events(ALLOCSTALL, sc->reclaim_idx, 1);
 
        do {
                vmpressure_prio(sc->gfp_mask, sc->target_mem_cgroup,
@@ -2692,7 +2841,7 @@ static bool pfmemalloc_watermark_ok(pg_data_t *pgdat)
        for (i = 0; i <= ZONE_NORMAL; i++) {
                zone = &pgdat->node_zones[i];
                if (!populated_zone(zone) ||
-                   zone_reclaimable_pages(zone) == 0)
+                   pgdat_reclaimable_pages(pgdat) == 0)
                        continue;
 
                pfmemalloc_reserve += min_wmark_pages(zone);
@@ -2707,7 +2856,7 @@ static bool pfmemalloc_watermark_ok(pg_data_t *pgdat)
 
        /* kswapd must be awake if processes are being throttled */
        if (!wmark_ok && waitqueue_active(&pgdat->kswapd_wait)) {
-               pgdat->classzone_idx = min(pgdat->classzone_idx,
+               pgdat->kswapd_classzone_idx = min(pgdat->kswapd_classzone_idx,
                                                (enum zone_type)ZONE_NORMAL);
                wake_up_interruptible(&pgdat->kswapd_wait);
        }
@@ -2815,6 +2964,7 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
        struct scan_control sc = {
                .nr_to_reclaim = SWAP_CLUSTER_MAX,
                .gfp_mask = (gfp_mask = memalloc_noio_flags(gfp_mask)),
+               .reclaim_idx = gfp_zone(gfp_mask),
                .order = order,
                .nodemask = nodemask,
                .priority = DEF_PRIORITY,
@@ -2833,7 +2983,8 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
 
        trace_mm_vmscan_direct_reclaim_begin(order,
                                sc.may_writepage,
-                               gfp_mask);
+                               gfp_mask,
+                               sc.reclaim_idx);
 
        nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
 
@@ -2844,9 +2995,9 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
 
 #ifdef CONFIG_MEMCG
 
-unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *memcg,
+unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg,
                                                gfp_t gfp_mask, bool noswap,
-                                               struct zone *zone,
+                                               pg_data_t *pgdat,
                                                unsigned long *nr_scanned)
 {
        struct scan_control sc = {
@@ -2854,6 +3005,7 @@ unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *memcg,
                .target_mem_cgroup = memcg,
                .may_writepage = !laptop_mode,
                .may_unmap = 1,
+               .reclaim_idx = MAX_NR_ZONES - 1,
                .may_swap = !noswap,
        };
        unsigned long lru_pages;
@@ -2863,16 +3015,17 @@ unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *memcg,
 
        trace_mm_vmscan_memcg_softlimit_reclaim_begin(sc.order,
                                                      sc.may_writepage,
-                                                     sc.gfp_mask);
+                                                     sc.gfp_mask,
+                                                     sc.reclaim_idx);
 
        /*
         * NOTE: Although we can get the priority field, using it
         * here is not a good idea, since it limits the pages we can scan.
-        * if we don't reclaim here, the shrink_zone from balance_pgdat
+        * if we don't reclaim here, the shrink_node from balance_pgdat
         * will pick up pages from other mem cgroup's as well. We hack
         * the priority and make it zero.
         */
-       shrink_zone_memcg(zone, memcg, &sc, &lru_pages);
+       shrink_node_memcg(pgdat, memcg, &sc, &lru_pages);
 
        trace_mm_vmscan_memcg_softlimit_reclaim_end(sc.nr_reclaimed);
 
@@ -2892,6 +3045,7 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
                .nr_to_reclaim = max(nr_pages, SWAP_CLUSTER_MAX),
                .gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
                                (GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK),
+               .reclaim_idx = MAX_NR_ZONES - 1,
                .target_mem_cgroup = memcg,
                .priority = DEF_PRIORITY,
                .may_writepage = !laptop_mode,
@@ -2910,7 +3064,8 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
 
        trace_mm_vmscan_memcg_reclaim_begin(0,
                                            sc.may_writepage,
-                                           sc.gfp_mask);
+                                           sc.gfp_mask,
+                                           sc.reclaim_idx);
 
        nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
 
@@ -2920,7 +3075,8 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
 }
 #endif
 
-static void age_active_anon(struct zone *zone, struct scan_control *sc)
+static void age_active_anon(struct pglist_data *pgdat,
+                               struct scan_control *sc)
 {
        struct mem_cgroup *memcg;
 
@@ -2929,9 +3085,9 @@ static void age_active_anon(struct zone *zone, struct scan_control *sc)
 
        memcg = mem_cgroup_iter(NULL, NULL, NULL);
        do {
-               struct lruvec *lruvec = mem_cgroup_zone_lruvec(zone, memcg);
+               struct lruvec *lruvec = mem_cgroup_lruvec(pgdat, memcg);
 
-               if (inactive_list_is_low(lruvec, false))
+               if (inactive_list_is_low(lruvec, false, sc))
                        shrink_active_list(SWAP_CLUSTER_MAX, lruvec,
                                           sc, LRU_ACTIVE_ANON);
 
@@ -2939,82 +3095,21 @@ static void age_active_anon(struct zone *zone, struct scan_control *sc)
        } while (memcg);
 }
 
-static bool zone_balanced(struct zone *zone, int order, bool highorder,
-                       unsigned long balance_gap, int classzone_idx)
+static bool zone_balanced(struct zone *zone, int order, int classzone_idx)
 {
-       unsigned long mark = high_wmark_pages(zone) + balance_gap;
+       unsigned long mark = high_wmark_pages(zone);
+
+       if (!zone_watermark_ok_safe(zone, order, mark, classzone_idx))
+               return false;
 
        /*
-        * When checking from pgdat_balanced(), kswapd should stop and sleep
-        * when it reaches the high order-0 watermark and let kcompactd take
-        * over. Other callers such as wakeup_kswapd() want to determine the
-        * true high-order watermark.
+        * If any eligible zone is balanced then the node is not considered
+        * to be congested or dirty
         */
-       if (IS_ENABLED(CONFIG_COMPACTION) && !highorder) {
-               mark += (1UL << order);
-               order = 0;
-       }
-
-       return zone_watermark_ok_safe(zone, order, mark, classzone_idx);
-}
-
-/*
- * pgdat_balanced() is used when checking if a node is balanced.
- *
- * For order-0, all zones must be balanced!
- *
- * For high-order allocations only zones that meet watermarks and are in a
- * zone allowed by the callers classzone_idx are added to balanced_pages. The
- * total of balanced pages must be at least 25% of the zones allowed by
- * classzone_idx for the node to be considered balanced. Forcing all zones to
- * be balanced for high orders can cause excessive reclaim when there are
- * imbalanced zones.
- * The choice of 25% is due to
- *   o a 16M DMA zone that is balanced will not balance a zone on any
- *     reasonable sized machine
- *   o On all other machines, the top zone must be at least a reasonable
- *     percentage of the middle zones. For example, on 32-bit x86, highmem
- *     would need to be at least 256M for it to be balance a whole node.
- *     Similarly, on x86-64 the Normal zone would need to be at least 1G
- *     to balance a node on its own. These seemed like reasonable ratios.
- */
-static bool pgdat_balanced(pg_data_t *pgdat, int order, int classzone_idx)
-{
-       unsigned long managed_pages = 0;
-       unsigned long balanced_pages = 0;
-       int i;
-
-       /* Check the watermark levels */
-       for (i = 0; i <= classzone_idx; i++) {
-               struct zone *zone = pgdat->node_zones + i;
-
-               if (!populated_zone(zone))
-                       continue;
-
-               managed_pages += zone->managed_pages;
-
-               /*
-                * A special case here:
-                *
-                * balance_pgdat() skips over all_unreclaimable after
-                * DEF_PRIORITY. Effectively, it considers them balanced so
-                * they must be considered balanced here as well!
-                */
-               if (!zone_reclaimable(zone)) {
-                       balanced_pages += zone->managed_pages;
-                       continue;
-               }
+       clear_bit(PGDAT_CONGESTED, &zone->zone_pgdat->flags);
+       clear_bit(PGDAT_DIRTY, &zone->zone_pgdat->flags);
 
-               if (zone_balanced(zone, order, false, 0, i))
-                       balanced_pages += zone->managed_pages;
-               else if (!order)
-                       return false;
-       }
-
-       if (order)
-               return balanced_pages >= (managed_pages >> 2);
-       else
-               return true;
+       return true;
 }
 
 /*
@@ -3023,12 +3118,9 @@ static bool pgdat_balanced(pg_data_t *pgdat, int order, int classzone_idx)
  *
  * Returns true if kswapd is ready to sleep
  */
-static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, long remaining,
-                                       int classzone_idx)
+static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, int classzone_idx)
 {
-       /* If a direct reclaimer woke kswapd within HZ/10, it's premature */
-       if (remaining)
-               return false;
+       int i;
 
        /*
         * The throttled processes are normally woken up in balance_pgdat() as
@@ -3046,91 +3138,81 @@ static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, long remaining,
        if (waitqueue_active(&pgdat->pfmemalloc_wait))
                wake_up_all(&pgdat->pfmemalloc_wait);
 
-       return pgdat_balanced(pgdat, order, classzone_idx);
+       for (i = 0; i <= classzone_idx; i++) {
+               struct zone *zone = pgdat->node_zones + i;
+
+               if (!populated_zone(zone))
+                       continue;
+
+               if (!zone_balanced(zone, order, classzone_idx))
+                       return false;
+       }
+
+       return true;
 }
 
 /*
- * kswapd shrinks the zone by the number of pages required to reach
- * the high watermark.
+ * kswapd shrinks a node of pages that are at or below the highest usable
+ * zone that is currently unbalanced.
  *
  * Returns true if kswapd scanned at least the requested number of pages to
  * reclaim or if the lack of progress was due to pages under writeback.
  * This is used to determine if the scanning priority needs to be raised.
  */
-static bool kswapd_shrink_zone(struct zone *zone,
-                              int classzone_idx,
+static bool kswapd_shrink_node(pg_data_t *pgdat,
                               struct scan_control *sc)
 {
-       unsigned long balance_gap;
-       bool lowmem_pressure;
+       struct zone *zone;
+       int z;
 
-       /* Reclaim above the high watermark. */
-       sc->nr_to_reclaim = max(SWAP_CLUSTER_MAX, high_wmark_pages(zone));
+       /* Reclaim a number of pages proportional to the number of zones */
+       sc->nr_to_reclaim = 0;
+       for (z = 0; z <= sc->reclaim_idx; z++) {
+               zone = pgdat->node_zones + z;
+               if (!populated_zone(zone))
+                       continue;
 
-       /*
-        * We put equal pressure on every zone, unless one zone has way too
-        * many pages free already. The "too many pages" is defined as the
-        * high wmark plus a "gap" where the gap is either the low
-        * watermark or 1% of the zone, whichever is smaller.
-        */
-       balance_gap = min(low_wmark_pages(zone), DIV_ROUND_UP(
-                       zone->managed_pages, KSWAPD_ZONE_BALANCE_GAP_RATIO));
+               sc->nr_to_reclaim += max(high_wmark_pages(zone), SWAP_CLUSTER_MAX);
+       }
 
        /*
-        * If there is no low memory pressure or the zone is balanced then no
-        * reclaim is necessary
+        * Historically care was taken to put equal pressure on all zones but
+        * now pressure is applied based on node LRU order.
         */
-       lowmem_pressure = (buffer_heads_over_limit && is_highmem(zone));
-       if (!lowmem_pressure && zone_balanced(zone, sc->order, false,
-                                               balance_gap, classzone_idx))
-               return true;
-
-       shrink_zone(zone, sc, zone_idx(zone) == classzone_idx);
-
-       clear_bit(ZONE_WRITEBACK, &zone->flags);
+       shrink_node(pgdat, sc);
 
        /*
-        * If a zone reaches its high watermark, consider it to be no longer
-        * congested. It's possible there are dirty pages backed by congested
-        * BDIs but as pressure is relieved, speculatively avoid congestion
-        * waits.
+        * Fragmentation may mean that the system cannot be rebalanced for
+        * high-order allocations. If twice the allocation size has been
+        * reclaimed then recheck watermarks only at order-0 to prevent
+        * excessive reclaim. Assume that a process requested a high-order
+        * can direct reclaim/compact.
         */
-       if (zone_reclaimable(zone) &&
-           zone_balanced(zone, sc->order, false, 0, classzone_idx)) {
-               clear_bit(ZONE_CONGESTED, &zone->flags);
-               clear_bit(ZONE_DIRTY, &zone->flags);
-       }
+       if (sc->order && sc->nr_reclaimed >= 2UL << sc->order)
+               sc->order = 0;
 
        return sc->nr_scanned >= sc->nr_to_reclaim;
 }
 
 /*
- * For kswapd, balance_pgdat() will work across all this node's zones until
- * they are all at high_wmark_pages(zone).
+ * For kswapd, balance_pgdat() will reclaim pages across a node from zones
+ * that are eligible for use by the caller until at least one zone is
+ * balanced.
  *
- * Returns the highest zone idx kswapd was reclaiming at
- *
- * There is special handling here for zones which are full of pinned pages.
- * This can happen if the pages are all mlocked, or if they are all used by
- * device drivers (say, ZONE_DMA).  Or if they are all in use by hugetlb.
- * What we do is to detect the case where all pages in the zone have been
- * scanned twice and there has been zero successful reclaim.  Mark the zone as
- * dead and from now on, only perform a short scan.  Basically we're polling
- * the zone for when the problem goes away.
+ * Returns the order kswapd finished reclaiming at.
  *
  * kswapd scans the zones in the highmem->normal->dma direction.  It skips
  * zones which have free_pages > high_wmark_pages(zone), but once a zone is
- * found to have free_pages <= high_wmark_pages(zone), we scan that zone and the
- * lower zones regardless of the number of free pages in the lower zones. This
- * interoperates with the page allocator fallback scheme to ensure that aging
- * of pages is balanced across the zones.
+ * found to have free_pages <= high_wmark_pages(zone), any page is that zone
+ * or lower is eligible for reclaim until at least one usable zone is
+ * balanced.
  */
 static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx)
 {
        int i;
-       int end_zone = 0;       /* Inclusive.  0 = ZONE_DMA */
        unsigned long nr_soft_reclaimed;
        unsigned long nr_soft_scanned;
+       struct zone *zone;
        struct scan_control sc = {
                .gfp_mask = GFP_KERNEL,
                .order = order,
@@ -3145,100 +3227,77 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx)
                bool raise_priority = true;
 
                sc.nr_reclaimed = 0;
+               sc.reclaim_idx = classzone_idx;
 
                /*
-                * Scan in the highmem->dma direction for the highest
-                * zone which needs scanning
+                * If the number of buffer_heads exceeds the maximum allowed
+                * then consider reclaiming from all zones. This has a dual
+                * purpose -- on 64-bit systems it is expected that
+                * buffer_heads are stripped during active rotation. On 32-bit
+                * systems, highmem pages can pin lowmem memory and shrinking
+                * buffers can relieve lowmem pressure. Reclaim may still not
+                * go ahead if all eligible zones for the original allocation
+                * request are balanced to avoid excessive reclaim from kswapd.
                 */
-               for (i = pgdat->nr_zones - 1; i >= 0; i--) {
-                       struct zone *zone = pgdat->node_zones + i;
-
-                       if (!populated_zone(zone))
-                               continue;
-
-                       if (sc.priority != DEF_PRIORITY &&
-                           !zone_reclaimable(zone))
-                               continue;
-
-                       /*
-                        * Do some background aging of the anon list, to give
-                        * pages a chance to be referenced before reclaiming.
-                        */
-                       age_active_anon(zone, &sc);
+               if (buffer_heads_over_limit) {
+                       for (i = MAX_NR_ZONES - 1; i >= 0; i--) {
+                               zone = pgdat->node_zones + i;
+                               if (!populated_zone(zone))
+                                       continue;
 
-                       /*
-                        * If the number of buffer_heads in the machine
-                        * exceeds the maximum allowed level and this node
-                        * has a highmem zone, force kswapd to reclaim from
-                        * it to relieve lowmem pressure.
-                        */
-                       if (buffer_heads_over_limit && is_highmem_idx(i)) {
-                               end_zone = i;
+                               sc.reclaim_idx = i;
                                break;
                        }
+               }
 
-                       if (!zone_balanced(zone, order, false, 0, 0)) {
-                               end_zone = i;
-                               break;
-                       } else {
-                               /*
-                                * If balanced, clear the dirty and congested
-                                * flags
-                                */
-                               clear_bit(ZONE_CONGESTED, &zone->flags);
-                               clear_bit(ZONE_DIRTY, &zone->flags);
-                       }
+               /*
+                * Only reclaim if there are no eligible zones. Check from
+                * high to low zone as allocations prefer higher zones.
+                * Scanning from low to high zone would allow congestion to be
+                * cleared during a very small window when a small low
+                * zone was balanced even under extreme pressure when the
+                * overall node may be congested. Note that sc.reclaim_idx
+                * is not used as buffer_heads_over_limit may have adjusted
+                * it.
+                */
+               for (i = classzone_idx; i >= 0; i--) {
+                       zone = pgdat->node_zones + i;
+                       if (!populated_zone(zone))
+                               continue;
+
+                       if (zone_balanced(zone, sc.order, classzone_idx))
+                               goto out;
                }
 
-               if (i < 0)
-                       goto out;
+               /*
+                * Do some background aging of the anon list, to give
+                * pages a chance to be referenced before reclaiming. All
+                * pages are rotated regardless of classzone as this is
+                * about consistent aging.
+                */
+               age_active_anon(pgdat, &sc);
 
                /*
                 * If we're getting trouble reclaiming, start doing writepage
                 * even in laptop mode.
                 */
-               if (sc.priority < DEF_PRIORITY - 2)
+               if (sc.priority < DEF_PRIORITY - 2 || !pgdat_reclaimable(pgdat))
                        sc.may_writepage = 1;
 
+               /* Call soft limit reclaim before calling shrink_node. */
+               sc.nr_scanned = 0;
+               nr_soft_scanned = 0;
+               nr_soft_reclaimed = mem_cgroup_soft_limit_reclaim(pgdat, sc.order,
+                                               sc.gfp_mask, &nr_soft_scanned);
+               sc.nr_reclaimed += nr_soft_reclaimed;
+
                /*
-                * Now scan the zone in the dma->highmem direction, stopping
-                * at the last zone which needs scanning.
-                *
-                * We do this because the page allocator works in the opposite
-                * direction.  This prevents the page allocator from allocating
-                * pages behind kswapd's direction of progress, which would
-                * cause too much scanning of the lower zones.
+                * There should be no need to raise the scanning priority if
+                * enough pages are already being scanned that that high
+                * watermark would be met at 100% efficiency.
                 */
-               for (i = 0; i <= end_zone; i++) {
-                       struct zone *zone = pgdat->node_zones + i;
-
-                       if (!populated_zone(zone))
-                               continue;
-
-                       if (sc.priority != DEF_PRIORITY &&
-                           !zone_reclaimable(zone))
-                               continue;
-
-                       sc.nr_scanned = 0;
-
-                       nr_soft_scanned = 0;
-                       /*
-                        * Call soft limit reclaim before calling shrink_zone.
-                        */
-                       nr_soft_reclaimed = mem_cgroup_soft_limit_reclaim(zone,
-                                                       order, sc.gfp_mask,
-                                                       &nr_soft_scanned);
-                       sc.nr_reclaimed += nr_soft_reclaimed;
-
-                       /*
-                        * There should be no need to raise the scanning
-                        * priority if enough pages are already being scanned
-                        * that that high watermark would be met at 100%
-                        * efficiency.
-                        */
-                       if (kswapd_shrink_zone(zone, end_zone, &sc))
-                               raise_priority = false;
-               }
+               if (kswapd_shrink_node(pgdat, &sc))
+                       raise_priority = false;
 
                /*
                 * If the low watermark is met there is no need for processes
@@ -3259,19 +3318,20 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx)
                 */
                if (raise_priority || !sc.nr_reclaimed)
                        sc.priority--;
-       } while (sc.priority >= 1 &&
-                       !pgdat_balanced(pgdat, order, classzone_idx));
+       } while (sc.priority >= 1);
 
 out:
        /*
-        * Return the highest zone idx we were reclaiming at so
-        * prepare_kswapd_sleep() makes the same decisions as here.
+        * Return the order kswapd stopped reclaiming at as
+        * prepare_kswapd_sleep() takes it into account. If another caller
+        * entered the allocator slow path while kswapd was awake, order will
+        * remain at the higher level.
         */
-       return end_zone;
+       return sc.order;
 }
 
-static void kswapd_try_to_sleep(pg_data_t *pgdat, int order,
-                               int classzone_idx, int balanced_classzone_idx)
+static void kswapd_try_to_sleep(pg_data_t *pgdat, int alloc_order, int reclaim_order,
+                               unsigned int classzone_idx)
 {
        long remaining = 0;
        DEFINE_WAIT(wait);
@@ -3282,8 +3342,7 @@ static void kswapd_try_to_sleep(pg_data_t *pgdat, int order,
        prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE);
 
        /* Try to sleep for a short interval */
-       if (prepare_kswapd_sleep(pgdat, order, remaining,
-                                               balanced_classzone_idx)) {
+       if (prepare_kswapd_sleep(pgdat, reclaim_order, classzone_idx)) {
                /*
                 * Compaction records what page blocks it recently failed to
                 * isolate pages from and skips them in the future scanning.
@@ -3296,9 +3355,20 @@ static void kswapd_try_to_sleep(pg_data_t *pgdat, int order,
                 * We have freed the memory, now we should compact it to make
                 * allocation of the requested order possible.
                 */
-               wakeup_kcompactd(pgdat, order, classzone_idx);
+               wakeup_kcompactd(pgdat, alloc_order, classzone_idx);
 
                remaining = schedule_timeout(HZ/10);
+
+               /*
+                * If woken prematurely then reset kswapd_classzone_idx and
+                * order. The values will either be from a wakeup request or
+                * the previous request that slept prematurely.
+                */
+               if (remaining) {
+                       pgdat->kswapd_classzone_idx = max(pgdat->kswapd_classzone_idx, classzone_idx);
+                       pgdat->kswapd_order = max(pgdat->kswapd_order, reclaim_order);
+               }
+
                finish_wait(&pgdat->kswapd_wait, &wait);
                prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE);
        }
@@ -3307,8 +3377,8 @@ static void kswapd_try_to_sleep(pg_data_t *pgdat, int order,
         * After a short sleep, check if it was a premature sleep. If not, then
         * go fully to sleep until explicitly woken up.
         */
-       if (prepare_kswapd_sleep(pgdat, order, remaining,
-                                               balanced_classzone_idx)) {
+       if (!remaining &&
+           prepare_kswapd_sleep(pgdat, reclaim_order, classzone_idx)) {
                trace_mm_vmscan_kswapd_sleep(pgdat->node_id);
 
                /*
@@ -3349,9 +3419,7 @@ static void kswapd_try_to_sleep(pg_data_t *pgdat, int order,
  */
 static int kswapd(void *p)
 {
-       unsigned long order, new_order;
-       int classzone_idx, new_classzone_idx;
-       int balanced_classzone_idx;
+       unsigned int alloc_order, reclaim_order, classzone_idx;
        pg_data_t *pgdat = (pg_data_t*)p;
        struct task_struct *tsk = current;
 
@@ -3381,38 +3449,20 @@ static int kswapd(void *p)
        tsk->flags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD;
        set_freezable();
 
-       order = new_order = 0;
-       classzone_idx = new_classzone_idx = pgdat->nr_zones - 1;
-       balanced_classzone_idx = classzone_idx;
+       pgdat->kswapd_order = alloc_order = reclaim_order = 0;
+       pgdat->kswapd_classzone_idx = classzone_idx = 0;
        for ( ; ; ) {
                bool ret;
 
-               /*
-                * While we were reclaiming, there might have been another
-                * wakeup, so check the values.
-                */
-               new_order = pgdat->kswapd_max_order;
-               new_classzone_idx = pgdat->classzone_idx;
-               pgdat->kswapd_max_order =  0;
-               pgdat->classzone_idx = pgdat->nr_zones - 1;
+kswapd_try_sleep:
+               kswapd_try_to_sleep(pgdat, alloc_order, reclaim_order,
+                                       classzone_idx);
 
-               if (order < new_order || classzone_idx > new_classzone_idx) {
-                       /*
-                        * Don't sleep if someone wants a larger 'order'
-                        * allocation or has tigher zone constraints
-                        */
-                       order = new_order;
-                       classzone_idx = new_classzone_idx;
-               } else {
-                       kswapd_try_to_sleep(pgdat, order, classzone_idx,
-                                               balanced_classzone_idx);
-                       order = pgdat->kswapd_max_order;
-                       classzone_idx = pgdat->classzone_idx;
-                       new_order = order;
-                       new_classzone_idx = classzone_idx;
-                       pgdat->kswapd_max_order = 0;
-                       pgdat->classzone_idx = pgdat->nr_zones - 1;
-               }
+               /* Read the new order and classzone_idx */
+               alloc_order = reclaim_order = pgdat->kswapd_order;
+               classzone_idx = pgdat->kswapd_classzone_idx;
+               pgdat->kswapd_order = 0;
+               pgdat->kswapd_classzone_idx = 0;
 
                ret = try_to_freeze();
                if (kthread_should_stop())
@@ -3422,11 +3472,25 @@ static int kswapd(void *p)
                 * We can speed up thawing tasks if we don't call balance_pgdat
                 * after returning from the refrigerator
                 */
-               if (!ret) {
-                       trace_mm_vmscan_kswapd_wake(pgdat->node_id, order);
-                       balanced_classzone_idx = balance_pgdat(pgdat, order,
-                                                               classzone_idx);
-               }
+               if (ret)
+                       continue;
+
+               /*
+                * Reclaim begins at the requested order but if a high-order
+                * reclaim fails then kswapd falls back to reclaiming for
+                * order-0. If that happens, kswapd will consider sleeping
+                * for the order it finished reclaiming at (reclaim_order)
+                * but kcompactd is woken to compact for the original
+                * request (alloc_order).
+                */
+               trace_mm_vmscan_kswapd_wake(pgdat->node_id, classzone_idx,
+                                               alloc_order);
+               reclaim_order = balance_pgdat(pgdat, alloc_order, classzone_idx);
+               if (reclaim_order < alloc_order)
+                       goto kswapd_try_sleep;
+
+               alloc_order = reclaim_order = pgdat->kswapd_order;
+               classzone_idx = pgdat->kswapd_classzone_idx;
        }
 
        tsk->flags &= ~(PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD);
@@ -3442,6 +3506,7 @@ static int kswapd(void *p)
 void wakeup_kswapd(struct zone *zone, int order, enum zone_type classzone_idx)
 {
        pg_data_t *pgdat;
+       int z;
 
        if (!populated_zone(zone))
                return;
@@ -3449,14 +3514,20 @@ void wakeup_kswapd(struct zone *zone, int order, enum zone_type classzone_idx)
        if (!cpuset_zone_allowed(zone, GFP_KERNEL | __GFP_HARDWALL))
                return;
        pgdat = zone->zone_pgdat;
-       if (pgdat->kswapd_max_order < order) {
-               pgdat->kswapd_max_order = order;
-               pgdat->classzone_idx = min(pgdat->classzone_idx, classzone_idx);
-       }
+       pgdat->kswapd_classzone_idx = max(pgdat->kswapd_classzone_idx, classzone_idx);
+       pgdat->kswapd_order = max(pgdat->kswapd_order, order);
        if (!waitqueue_active(&pgdat->kswapd_wait))
                return;
-       if (zone_balanced(zone, order, true, 0, 0))
-               return;
+
+       /* Only wake kswapd if all zones are unbalanced */
+       for (z = 0; z <= classzone_idx; z++) {
+               zone = pgdat->node_zones + z;
+               if (!populated_zone(zone))
+                       continue;
+
+               if (zone_balanced(zone, order, classzone_idx))
+                       return;
+       }
 
        trace_mm_vmscan_wakeup_kswapd(pgdat->node_id, zone_idx(zone), order);
        wake_up_interruptible(&pgdat->kswapd_wait);
@@ -3477,6 +3548,7 @@ unsigned long shrink_all_memory(unsigned long nr_to_reclaim)
        struct scan_control sc = {
                .nr_to_reclaim = nr_to_reclaim,
                .gfp_mask = GFP_HIGHUSER_MOVABLE,
+               .reclaim_idx = MAX_NR_ZONES - 1,
                .priority = DEF_PRIORITY,
                .may_writepage = 1,
                .may_unmap = 1,
@@ -3578,12 +3650,12 @@ module_init(kswapd_init)
 
 #ifdef CONFIG_NUMA
 /*
- * Zone reclaim mode
+ * Node reclaim mode
  *
- * If non-zero call zone_reclaim when the number of free pages falls below
+ * If non-zero call node_reclaim when the number of free pages falls below
  * the watermarks.
  */
-int zone_reclaim_mode __read_mostly;
+int node_reclaim_mode __read_mostly;
 
 #define RECLAIM_OFF 0
 #define RECLAIM_ZONE (1<<0)    /* Run shrink_inactive_list on the zone */
@@ -3591,14 +3663,14 @@ int zone_reclaim_mode __read_mostly;
 #define RECLAIM_UNMAP (1<<2)   /* Unmap pages during reclaim */
 
 /*
- * Priority for ZONE_RECLAIM. This determines the fraction of pages
+ * Priority for NODE_RECLAIM. This determines the fraction of pages
  * of a node considered for each zone_reclaim. 4 scans 1/16th of
  * a zone.
  */
-#define ZONE_RECLAIM_PRIORITY 4
+#define NODE_RECLAIM_PRIORITY 4
 
 /*
- * Percentage of pages in a zone that must be unmapped for zone_reclaim to
+ * Percentage of pages in a zone that must be unmapped for node_reclaim to
  * occur.
  */
 int sysctl_min_unmapped_ratio = 1;
@@ -3609,11 +3681,11 @@ int sysctl_min_unmapped_ratio = 1;
  */
 int sysctl_min_slab_ratio = 5;
 
-static inline unsigned long zone_unmapped_file_pages(struct zone *zone)
+static inline unsigned long node_unmapped_file_pages(struct pglist_data *pgdat)
 {
-       unsigned long file_mapped = zone_page_state(zone, NR_FILE_MAPPED);
-       unsigned long file_lru = zone_page_state(zone, NR_INACTIVE_FILE) +
-               zone_page_state(zone, NR_ACTIVE_FILE);
+       unsigned long file_mapped = node_page_state(pgdat, NR_FILE_MAPPED);
+       unsigned long file_lru = node_page_state(pgdat, NR_INACTIVE_FILE) +
+               node_page_state(pgdat, NR_ACTIVE_FILE);
 
        /*
         * It's possible for there to be more file mapped pages than
@@ -3624,7 +3696,7 @@ static inline unsigned long zone_unmapped_file_pages(struct zone *zone)
 }
 
 /* Work out how many page cache pages we can reclaim in this reclaim_mode */
-static unsigned long zone_pagecache_reclaimable(struct zone *zone)
+static unsigned long node_pagecache_reclaimable(struct pglist_data *pgdat)
 {
        unsigned long nr_pagecache_reclaimable;
        unsigned long delta = 0;
@@ -3632,17 +3704,17 @@ static unsigned long zone_pagecache_reclaimable(struct zone *zone)
        /*
         * If RECLAIM_UNMAP is set, then all file pages are considered
         * potentially reclaimable. Otherwise, we have to worry about
-        * pages like swapcache and zone_unmapped_file_pages() provides
+        * pages like swapcache and node_unmapped_file_pages() provides
         * a better estimate
         */
-       if (zone_reclaim_mode & RECLAIM_UNMAP)
-               nr_pagecache_reclaimable = zone_page_state(zone, NR_FILE_PAGES);
+       if (node_reclaim_mode & RECLAIM_UNMAP)
+               nr_pagecache_reclaimable = node_page_state(pgdat, NR_FILE_PAGES);
        else
-               nr_pagecache_reclaimable = zone_unmapped_file_pages(zone);
+               nr_pagecache_reclaimable = node_unmapped_file_pages(pgdat);
 
        /* If we can't clean pages, remove dirty pages from consideration */
-       if (!(zone_reclaim_mode & RECLAIM_WRITE))
-               delta += zone_page_state(zone, NR_FILE_DIRTY);
+       if (!(node_reclaim_mode & RECLAIM_WRITE))
+               delta += node_page_state(pgdat, NR_FILE_DIRTY);
 
        /* Watch for any possible underflows due to delta */
        if (unlikely(delta > nr_pagecache_reclaimable))
@@ -3652,22 +3724,24 @@ static unsigned long zone_pagecache_reclaimable(struct zone *zone)
 }
 
 /*
- * Try to free up some pages from this zone through reclaim.
+ * Try to free up some pages from this node through reclaim.
  */
-static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
+static int __node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned int order)
 {
        /* Minimum pages needed in order to stay on node */
        const unsigned long nr_pages = 1 << order;
        struct task_struct *p = current;
        struct reclaim_state reclaim_state;
+       int classzone_idx = gfp_zone(gfp_mask);
        struct scan_control sc = {
                .nr_to_reclaim = max(nr_pages, SWAP_CLUSTER_MAX),
                .gfp_mask = (gfp_mask = memalloc_noio_flags(gfp_mask)),
                .order = order,
-               .priority = ZONE_RECLAIM_PRIORITY,
-               .may_writepage = !!(zone_reclaim_mode & RECLAIM_WRITE),
-               .may_unmap = !!(zone_reclaim_mode & RECLAIM_UNMAP),
+               .priority = NODE_RECLAIM_PRIORITY,
+               .may_writepage = !!(node_reclaim_mode & RECLAIM_WRITE),
+               .may_unmap = !!(node_reclaim_mode & RECLAIM_UNMAP),
                .may_swap = 1,
+               .reclaim_idx = classzone_idx,
        };
 
        cond_resched();
@@ -3681,13 +3755,13 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
        reclaim_state.reclaimed_slab = 0;
        p->reclaim_state = &reclaim_state;
 
-       if (zone_pagecache_reclaimable(zone) > zone->min_unmapped_pages) {
+       if (node_pagecache_reclaimable(pgdat) > pgdat->min_unmapped_pages) {
                /*
                 * Free memory by calling shrink zone with increasing
                 * priorities until we have enough memory freed.
                 */
                do {
-                       shrink_zone(zone, &sc, true);
+                       shrink_node(pgdat, &sc);
                } while (sc.nr_reclaimed < nr_pages && --sc.priority >= 0);
        }
 
@@ -3697,49 +3771,47 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
        return sc.nr_reclaimed >= nr_pages;
 }
 
-int zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
+int node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned int order)
 {
-       int node_id;
        int ret;
 
        /*
-        * Zone reclaim reclaims unmapped file backed pages and
+        * Node reclaim reclaims unmapped file backed pages and
         * slab pages if we are over the defined limits.
         *
         * A small portion of unmapped file backed pages is needed for
         * file I/O otherwise pages read by file I/O will be immediately
-        * thrown out if the zone is overallocated. So we do not reclaim
-        * if less than a specified percentage of the zone is used by
+        * thrown out if the node is overallocated. So we do not reclaim
+        * if less than a specified percentage of the node is used by
         * unmapped file backed pages.
         */
-       if (zone_pagecache_reclaimable(zone) <= zone->min_unmapped_pages &&
-           zone_page_state(zone, NR_SLAB_RECLAIMABLE) <= zone->min_slab_pages)
-               return ZONE_RECLAIM_FULL;
+       if (node_pagecache_reclaimable(pgdat) <= pgdat->min_unmapped_pages &&
+           sum_zone_node_page_state(pgdat->node_id, NR_SLAB_RECLAIMABLE) <= pgdat->min_slab_pages)
+               return NODE_RECLAIM_FULL;
 
-       if (!zone_reclaimable(zone))
-               return ZONE_RECLAIM_FULL;
+       if (!pgdat_reclaimable(pgdat))
+               return NODE_RECLAIM_FULL;
 
        /*
         * Do not scan if the allocation should not be delayed.
         */
        if (!gfpflags_allow_blocking(gfp_mask) || (current->flags & PF_MEMALLOC))
-               return ZONE_RECLAIM_NOSCAN;
+               return NODE_RECLAIM_NOSCAN;
 
        /*
-        * Only run zone reclaim on the local zone or on zones that do not
+        * Only run node reclaim on the local node or on nodes that do not
         * have associated processors. This will favor the local processor
         * over remote processors and spread off node memory allocations
         * as wide as possible.
         */
-       node_id = zone_to_nid(zone);
-       if (node_state(node_id, N_CPU) && node_id != numa_node_id())
-               return ZONE_RECLAIM_NOSCAN;
+       if (node_state(pgdat->node_id, N_CPU) && pgdat->node_id != numa_node_id())
+               return NODE_RECLAIM_NOSCAN;
 
-       if (test_and_set_bit(ZONE_RECLAIM_LOCKED, &zone->flags))
-               return ZONE_RECLAIM_NOSCAN;
+       if (test_and_set_bit(PGDAT_RECLAIM_LOCKED, &pgdat->flags))
+               return NODE_RECLAIM_NOSCAN;
 
-       ret = __zone_reclaim(zone, gfp_mask, order);
-       clear_bit(ZONE_RECLAIM_LOCKED, &zone->flags);
+       ret = __node_reclaim(pgdat, gfp_mask, order);
+       clear_bit(PGDAT_RECLAIM_LOCKED, &pgdat->flags);
 
        if (!ret)
                count_vm_event(PGSCAN_ZONE_RECLAIM_FAILED);
@@ -3778,24 +3850,23 @@ int page_evictable(struct page *page)
 void check_move_unevictable_pages(struct page **pages, int nr_pages)
 {
        struct lruvec *lruvec;
-       struct zone *zone = NULL;
+       struct pglist_data *pgdat = NULL;
        int pgscanned = 0;
        int pgrescued = 0;
        int i;
 
        for (i = 0; i < nr_pages; i++) {
                struct page *page = pages[i];
-               struct zone *pagezone;
+               struct pglist_data *pagepgdat = page_pgdat(page);
 
                pgscanned++;
-               pagezone = page_zone(page);
-               if (pagezone != zone) {
-                       if (zone)
-                               spin_unlock_irq(&zone->lru_lock);
-                       zone = pagezone;
-                       spin_lock_irq(&zone->lru_lock);
+               if (pagepgdat != pgdat) {
+                       if (pgdat)
+                               spin_unlock_irq(&pgdat->lru_lock);
+                       pgdat = pagepgdat;
+                       spin_lock_irq(&pgdat->lru_lock);
                }
-               lruvec = mem_cgroup_page_lruvec(page, zone);
+               lruvec = mem_cgroup_page_lruvec(page, pgdat);
 
                if (!PageLRU(page) || !PageUnevictable(page))
                        continue;
@@ -3811,10 +3882,10 @@ void check_move_unevictable_pages(struct page **pages, int nr_pages)
                }
        }
 
-       if (zone) {
+       if (pgdat) {
                __count_vm_events(UNEVICTABLE_PGRESCUED, pgrescued);
                __count_vm_events(UNEVICTABLE_PGSCANNED, pgscanned);
-               spin_unlock_irq(&zone->lru_lock);
+               spin_unlock_irq(&pgdat->lru_lock);
        }
 }
 #endif /* CONFIG_SHMEM */
index 7997f52..89cec42 100644 (file)
@@ -86,8 +86,10 @@ void vm_events_fold_cpu(int cpu)
  *
  * vm_stat contains the global counters
  */
-atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS] __cacheline_aligned_in_smp;
-EXPORT_SYMBOL(vm_stat);
+atomic_long_t vm_zone_stat[NR_VM_ZONE_STAT_ITEMS] __cacheline_aligned_in_smp;
+atomic_long_t vm_node_stat[NR_VM_NODE_STAT_ITEMS] __cacheline_aligned_in_smp;
+EXPORT_SYMBOL(vm_zone_stat);
+EXPORT_SYMBOL(vm_node_stat);
 
 #ifdef CONFIG_SMP
 
@@ -167,19 +169,36 @@ int calculate_normal_threshold(struct zone *zone)
  */
 void refresh_zone_stat_thresholds(void)
 {
+       struct pglist_data *pgdat;
        struct zone *zone;
        int cpu;
        int threshold;
 
+       /* Zero current pgdat thresholds */
+       for_each_online_pgdat(pgdat) {
+               for_each_online_cpu(cpu) {
+                       per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold = 0;
+               }
+       }
+
        for_each_populated_zone(zone) {
+               struct pglist_data *pgdat = zone->zone_pgdat;
                unsigned long max_drift, tolerate_drift;
 
                threshold = calculate_normal_threshold(zone);
 
-               for_each_online_cpu(cpu)
+               for_each_online_cpu(cpu) {
+                       int pgdat_threshold;
+
                        per_cpu_ptr(zone->pageset, cpu)->stat_threshold
                                                        = threshold;
 
+                       /* Base nodestat threshold on the largest populated zone. */
+                       pgdat_threshold = per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold;
+                       per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold
+                               = max(threshold, pgdat_threshold);
+               }
+
                /*
                 * Only set percpu_drift_mark if there is a danger that
                 * NR_FREE_PAGES reports the low watermark is ok when in fact
@@ -238,6 +257,26 @@ void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
 }
 EXPORT_SYMBOL(__mod_zone_page_state);
 
+void __mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item,
+                               long delta)
+{
+       struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
+       s8 __percpu *p = pcp->vm_node_stat_diff + item;
+       long x;
+       long t;
+
+       x = delta + __this_cpu_read(*p);
+
+       t = __this_cpu_read(pcp->stat_threshold);
+
+       if (unlikely(x > t || x < -t)) {
+               node_page_state_add(x, pgdat, item);
+               x = 0;
+       }
+       __this_cpu_write(*p, x);
+}
+EXPORT_SYMBOL(__mod_node_page_state);
+
 /*
  * Optimized increment and decrement functions.
  *
@@ -277,12 +316,34 @@ void __inc_zone_state(struct zone *zone, enum zone_stat_item item)
        }
 }
 
+void __inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
+{
+       struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
+       s8 __percpu *p = pcp->vm_node_stat_diff + item;
+       s8 v, t;
+
+       v = __this_cpu_inc_return(*p);
+       t = __this_cpu_read(pcp->stat_threshold);
+       if (unlikely(v > t)) {
+               s8 overstep = t >> 1;
+
+               node_page_state_add(v + overstep, pgdat, item);
+               __this_cpu_write(*p, -overstep);
+       }
+}
+
 void __inc_zone_page_state(struct page *page, enum zone_stat_item item)
 {
        __inc_zone_state(page_zone(page), item);
 }
 EXPORT_SYMBOL(__inc_zone_page_state);
 
+void __inc_node_page_state(struct page *page, enum node_stat_item item)
+{
+       __inc_node_state(page_pgdat(page), item);
+}
+EXPORT_SYMBOL(__inc_node_page_state);
+
 void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
 {
        struct per_cpu_pageset __percpu *pcp = zone->pageset;
@@ -299,12 +360,34 @@ void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
        }
 }
 
+void __dec_node_state(struct pglist_data *pgdat, enum node_stat_item item)
+{
+       struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
+       s8 __percpu *p = pcp->vm_node_stat_diff + item;
+       s8 v, t;
+
+       v = __this_cpu_dec_return(*p);
+       t = __this_cpu_read(pcp->stat_threshold);
+       if (unlikely(v < - t)) {
+               s8 overstep = t >> 1;
+
+               node_page_state_add(v - overstep, pgdat, item);
+               __this_cpu_write(*p, overstep);
+       }
+}
+
 void __dec_zone_page_state(struct page *page, enum zone_stat_item item)
 {
        __dec_zone_state(page_zone(page), item);
 }
 EXPORT_SYMBOL(__dec_zone_page_state);
 
+void __dec_node_page_state(struct page *page, enum node_stat_item item)
+{
+       __dec_node_state(page_pgdat(page), item);
+}
+EXPORT_SYMBOL(__dec_node_page_state);
+
 #ifdef CONFIG_HAVE_CMPXCHG_LOCAL
 /*
  * If we have cmpxchg_local support then we do not need to incur the overhead
@@ -318,8 +401,8 @@ EXPORT_SYMBOL(__dec_zone_page_state);
  *     1       Overstepping half of threshold
  *     -1      Overstepping minus half of threshold
 */
-static inline void mod_state(struct zone *zone, enum zone_stat_item item,
-                            long delta, int overstep_mode)
+static inline void mod_zone_state(struct zone *zone,
+       enum zone_stat_item item, long delta, int overstep_mode)
 {
        struct per_cpu_pageset __percpu *pcp = zone->pageset;
        s8 __percpu *p = pcp->vm_stat_diff + item;
@@ -359,26 +442,83 @@ static inline void mod_state(struct zone *zone, enum zone_stat_item item,
 void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
                         long delta)
 {
-       mod_state(zone, item, delta, 0);
+       mod_zone_state(zone, item, delta, 0);
 }
 EXPORT_SYMBOL(mod_zone_page_state);
 
-void inc_zone_state(struct zone *zone, enum zone_stat_item item)
-{
-       mod_state(zone, item, 1, 1);
-}
-
 void inc_zone_page_state(struct page *page, enum zone_stat_item item)
 {
-       mod_state(page_zone(page), item, 1, 1);
+       mod_zone_state(page_zone(page), item, 1, 1);
 }
 EXPORT_SYMBOL(inc_zone_page_state);
 
 void dec_zone_page_state(struct page *page, enum zone_stat_item item)
 {
-       mod_state(page_zone(page), item, -1, -1);
+       mod_zone_state(page_zone(page), item, -1, -1);
 }
 EXPORT_SYMBOL(dec_zone_page_state);
+
+static inline void mod_node_state(struct pglist_data *pgdat,
+       enum node_stat_item item, int delta, int overstep_mode)
+{
+       struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
+       s8 __percpu *p = pcp->vm_node_stat_diff + item;
+       long o, n, t, z;
+
+       do {
+               z = 0;  /* overflow to node counters */
+
+               /*
+                * The fetching of the stat_threshold is racy. We may apply
+                * a counter threshold to the wrong the cpu if we get
+                * rescheduled while executing here. However, the next
+                * counter update will apply the threshold again and
+                * therefore bring the counter under the threshold again.
+                *
+                * Most of the time the thresholds are the same anyways
+                * for all cpus in a node.
+                */
+               t = this_cpu_read(pcp->stat_threshold);
+
+               o = this_cpu_read(*p);
+               n = delta + o;
+
+               if (n > t || n < -t) {
+                       int os = overstep_mode * (t >> 1) ;
+
+                       /* Overflow must be added to node counters */
+                       z = n + os;
+                       n = -os;
+               }
+       } while (this_cpu_cmpxchg(*p, o, n) != o);
+
+       if (z)
+               node_page_state_add(z, pgdat, item);
+}
+
+void mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item,
+                                       long delta)
+{
+       mod_node_state(pgdat, item, delta, 0);
+}
+EXPORT_SYMBOL(mod_node_page_state);
+
+void inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
+{
+       mod_node_state(pgdat, item, 1, 1);
+}
+
+void inc_node_page_state(struct page *page, enum node_stat_item item)
+{
+       mod_node_state(page_pgdat(page), item, 1, 1);
+}
+EXPORT_SYMBOL(inc_node_page_state);
+
+void dec_node_page_state(struct page *page, enum node_stat_item item)
+{
+       mod_node_state(page_pgdat(page), item, -1, -1);
+}
+EXPORT_SYMBOL(dec_node_page_state);
 #else
 /*
  * Use interrupt disable to serialize counter updates
@@ -394,15 +534,6 @@ void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
 }
 EXPORT_SYMBOL(mod_zone_page_state);
 
-void inc_zone_state(struct zone *zone, enum zone_stat_item item)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       __inc_zone_state(zone, item);
-       local_irq_restore(flags);
-}
-
 void inc_zone_page_state(struct page *page, enum zone_stat_item item)
 {
        unsigned long flags;
@@ -424,21 +555,69 @@ void dec_zone_page_state(struct page *page, enum zone_stat_item item)
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL(dec_zone_page_state);
-#endif
 
+void inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       __inc_node_state(pgdat, item);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL(inc_node_state);
+
+void mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item,
+                                       long delta)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       __mod_node_page_state(pgdat, item, delta);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL(mod_node_page_state);
+
+void inc_node_page_state(struct page *page, enum node_stat_item item)
+{
+       unsigned long flags;
+       struct pglist_data *pgdat;
+
+       pgdat = page_pgdat(page);
+       local_irq_save(flags);
+       __inc_node_state(pgdat, item);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL(inc_node_page_state);
+
+void dec_node_page_state(struct page *page, enum node_stat_item item)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       __dec_node_page_state(page, item);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL(dec_node_page_state);
+#endif
 
 /*
  * Fold a differential into the global counters.
  * Returns the number of counters updated.
  */
-static int fold_diff(int *diff)
+static int fold_diff(int *zone_diff, int *node_diff)
 {
        int i;
        int changes = 0;
 
        for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
-               if (diff[i]) {
-                       atomic_long_add(diff[i], &vm_stat[i]);
+               if (zone_diff[i]) {
+                       atomic_long_add(zone_diff[i], &vm_zone_stat[i]);
+                       changes++;
+       }
+
+       for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
+               if (node_diff[i]) {
+                       atomic_long_add(node_diff[i], &vm_node_stat[i]);
                        changes++;
        }
        return changes;
@@ -462,9 +641,11 @@ static int fold_diff(int *diff)
  */
 static int refresh_cpu_vm_stats(bool do_pagesets)
 {
+       struct pglist_data *pgdat;
        struct zone *zone;
        int i;
-       int global_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
+       int global_zone_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
+       int global_node_diff[NR_VM_NODE_STAT_ITEMS] = { 0, };
        int changes = 0;
 
        for_each_populated_zone(zone) {
@@ -477,7 +658,7 @@ static int refresh_cpu_vm_stats(bool do_pagesets)
                        if (v) {
 
                                atomic_long_add(v, &zone->vm_stat[i]);
-                               global_diff[i] += v;
+                               global_zone_diff[i] += v;
 #ifdef CONFIG_NUMA
                                /* 3 seconds idle till flush */
                                __this_cpu_write(p->expire, 3);
@@ -516,7 +697,22 @@ static int refresh_cpu_vm_stats(bool do_pagesets)
                }
 #endif
        }
-       changes += fold_diff(global_diff);
+
+       for_each_online_pgdat(pgdat) {
+               struct per_cpu_nodestat __percpu *p = pgdat->per_cpu_nodestats;
+
+               for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) {
+                       int v;
+
+                       v = this_cpu_xchg(p->vm_node_stat_diff[i], 0);
+                       if (v) {
+                               atomic_long_add(v, &pgdat->vm_stat[i]);
+                               global_node_diff[i] += v;
+                       }
+               }
+       }
+
+       changes += fold_diff(global_zone_diff, global_node_diff);
        return changes;
 }
 
@@ -527,9 +723,11 @@ static int refresh_cpu_vm_stats(bool do_pagesets)
  */
 void cpu_vm_stats_fold(int cpu)
 {
+       struct pglist_data *pgdat;
        struct zone *zone;
        int i;
-       int global_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
+       int global_zone_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
+       int global_node_diff[NR_VM_NODE_STAT_ITEMS] = { 0, };
 
        for_each_populated_zone(zone) {
                struct per_cpu_pageset *p;
@@ -543,11 +741,27 @@ void cpu_vm_stats_fold(int cpu)
                                v = p->vm_stat_diff[i];
                                p->vm_stat_diff[i] = 0;
                                atomic_long_add(v, &zone->vm_stat[i]);
-                               global_diff[i] += v;
+                               global_zone_diff[i] += v;
                        }
        }
 
-       fold_diff(global_diff);
+       for_each_online_pgdat(pgdat) {
+               struct per_cpu_nodestat *p;
+
+               p = per_cpu_ptr(pgdat->per_cpu_nodestats, cpu);
+
+               for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
+                       if (p->vm_node_stat_diff[i]) {
+                               int v;
+
+                               v = p->vm_node_stat_diff[i];
+                               p->vm_node_stat_diff[i] = 0;
+                               atomic_long_add(v, &pgdat->vm_stat[i]);
+                               global_node_diff[i] += v;
+                       }
+       }
+
+       fold_diff(global_zone_diff, global_node_diff);
 }
 
 /*
@@ -563,16 +777,19 @@ void drain_zonestat(struct zone *zone, struct per_cpu_pageset *pset)
                        int v = pset->vm_stat_diff[i];
                        pset->vm_stat_diff[i] = 0;
                        atomic_long_add(v, &zone->vm_stat[i]);
-                       atomic_long_add(v, &vm_stat[i]);
+                       atomic_long_add(v, &vm_zone_stat[i]);
                }
 }
 #endif
 
 #ifdef CONFIG_NUMA
 /*
- * Determine the per node value of a stat item.
+ * Determine the per node value of a stat item. This function
+ * is called frequently in a NUMA machine, so try to be as
+ * frugal as possible.
  */
-unsigned long node_page_state(int node, enum zone_stat_item item)
+unsigned long sum_zone_node_page_state(int node,
+                                enum zone_stat_item item)
 {
        struct zone *zones = NODE_DATA(node)->node_zones;
        int i;
@@ -584,6 +801,19 @@ unsigned long node_page_state(int node, enum zone_stat_item item)
        return count;
 }
 
+/*
+ * Determine the per node value of a stat item.
+ */
+unsigned long node_page_state(struct pglist_data *pgdat,
+                               enum node_stat_item item)
+{
+       long x = atomic_long_read(&pgdat->vm_stat[item]);
+#ifdef CONFIG_SMP
+       if (x < 0)
+               x = 0;
+#endif
+       return x;
+}
 #endif
 
 #ifdef CONFIG_COMPACTION
@@ -691,33 +921,18 @@ int fragmentation_index(struct zone *zone, unsigned int order)
 const char * const vmstat_text[] = {
        /* enum zone_stat_item countes */
        "nr_free_pages",
-       "nr_alloc_batch",
-       "nr_inactive_anon",
-       "nr_active_anon",
-       "nr_inactive_file",
-       "nr_active_file",
-       "nr_unevictable",
+       "nr_zone_inactive_anon",
+       "nr_zone_active_anon",
+       "nr_zone_inactive_file",
+       "nr_zone_active_file",
+       "nr_zone_unevictable",
+       "nr_zone_write_pending",
        "nr_mlock",
-       "nr_anon_pages",
-       "nr_mapped",
-       "nr_file_pages",
-       "nr_dirty",
-       "nr_writeback",
        "nr_slab_reclaimable",
        "nr_slab_unreclaimable",
        "nr_page_table_pages",
        "nr_kernel_stack",
-       "nr_unstable",
        "nr_bounce",
-       "nr_vmscan_write",
-       "nr_vmscan_immediate_reclaim",
-       "nr_writeback_temp",
-       "nr_isolated_anon",
-       "nr_isolated_file",
-       "nr_shmem",
-       "nr_dirtied",
-       "nr_written",
-       "nr_pages_scanned",
 #if IS_ENABLED(CONFIG_ZSMALLOC)
        "nr_zspages",
 #endif
@@ -729,13 +944,35 @@ const char * const vmstat_text[] = {
        "numa_local",
        "numa_other",
 #endif
+       "nr_free_cma",
+
+       /* Node-based counters */
+       "nr_inactive_anon",
+       "nr_active_anon",
+       "nr_inactive_file",
+       "nr_active_file",
+       "nr_unevictable",
+       "nr_isolated_anon",
+       "nr_isolated_file",
+       "nr_pages_scanned",
        "workingset_refault",
        "workingset_activate",
        "workingset_nodereclaim",
-       "nr_anon_transparent_hugepages",
+       "nr_anon_pages",
+       "nr_mapped",
+       "nr_file_pages",
+       "nr_dirty",
+       "nr_writeback",
+       "nr_writeback_temp",
+       "nr_shmem",
        "nr_shmem_hugepages",
        "nr_shmem_pmdmapped",
-       "nr_free_cma",
+       "nr_anon_transparent_hugepages",
+       "nr_unstable",
+       "nr_vmscan_write",
+       "nr_vmscan_immediate_reclaim",
+       "nr_dirtied",
+       "nr_written",
 
        /* enum writeback_stat_item counters */
        "nr_dirty_threshold",
@@ -749,6 +986,8 @@ const char * const vmstat_text[] = {
        "pswpout",
 
        TEXTS_FOR_ZONES("pgalloc")
+       TEXTS_FOR_ZONES("allocstall")
+       TEXTS_FOR_ZONES("pgskip")
 
        "pgfree",
        "pgactivate",
@@ -758,11 +997,11 @@ const char * const vmstat_text[] = {
        "pgmajfault",
        "pglazyfreed",
 
-       TEXTS_FOR_ZONES("pgrefill")
-       TEXTS_FOR_ZONES("pgsteal_kswapd")
-       TEXTS_FOR_ZONES("pgsteal_direct")
-       TEXTS_FOR_ZONES("pgscan_kswapd")
-       TEXTS_FOR_ZONES("pgscan_direct")
+       "pgrefill",
+       "pgsteal_kswapd",
+       "pgsteal_direct",
+       "pgscan_kswapd",
+       "pgscan_direct",
        "pgscan_direct_throttle",
 
 #ifdef CONFIG_NUMA
@@ -774,7 +1013,6 @@ const char * const vmstat_text[] = {
        "kswapd_low_wmark_hit_quickly",
        "kswapd_high_wmark_hit_quickly",
        "pageoutrun",
-       "allocstall",
 
        "pgrotated",
 
@@ -1180,17 +1418,41 @@ static const struct file_operations pagetypeinfo_file_ops = {
        .release        = seq_release,
 };
 
+static bool is_zone_first_populated(pg_data_t *pgdat, struct zone *zone)
+{
+       int zid;
+
+       for (zid = 0; zid < MAX_NR_ZONES; zid++) {
+               struct zone *compare = &pgdat->node_zones[zid];
+
+               if (populated_zone(compare))
+                       return zone == compare;
+       }
+
+       /* The zone must be somewhere! */
+       WARN_ON_ONCE(1);
+       return false;
+}
+
 static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
                                                        struct zone *zone)
 {
        int i;
        seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name);
+       if (is_zone_first_populated(pgdat, zone)) {
+               seq_printf(m, "\n  per-node stats");
+               for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) {
+                       seq_printf(m, "\n      %-12s %lu",
+                               vmstat_text[i + NR_VM_ZONE_STAT_ITEMS],
+                               node_page_state(pgdat, i));
+               }
+       }
        seq_printf(m,
                   "\n  pages free     %lu"
                   "\n        min      %lu"
                   "\n        low      %lu"
                   "\n        high     %lu"
-                  "\n        scanned  %lu"
+                  "\n   node_scanned  %lu"
                   "\n        spanned  %lu"
                   "\n        present  %lu"
                   "\n        managed  %lu",
@@ -1198,13 +1460,13 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
                   min_wmark_pages(zone),
                   low_wmark_pages(zone),
                   high_wmark_pages(zone),
-                  zone_page_state(zone, NR_PAGES_SCANNED),
+                  node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED),
                   zone->spanned_pages,
                   zone->present_pages,
                   zone->managed_pages);
 
        for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
-               seq_printf(m, "\n    %-12s %lu", vmstat_text[i],
+               seq_printf(m, "\n      %-12s %lu", vmstat_text[i],
                                zone_page_state(zone, i));
 
        seq_printf(m,
@@ -1234,12 +1496,12 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
 #endif
        }
        seq_printf(m,
-                  "\n  all_unreclaimable: %u"
-                  "\n  start_pfn:         %lu"
-                  "\n  inactive_ratio:    %u",
-                  !zone_reclaimable(zone),
+                  "\n  node_unreclaimable:  %u"
+                  "\n  start_pfn:           %lu"
+                  "\n  node_inactive_ratio: %u",
+                  !pgdat_reclaimable(zone->zone_pgdat),
                   zone->zone_start_pfn,
-                  zone->inactive_ratio);
+                  zone->zone_pgdat->inactive_ratio);
        seq_putc(m, '\n');
 }
 
@@ -1287,6 +1549,7 @@ static void *vmstat_start(struct seq_file *m, loff_t *pos)
        if (*pos >= ARRAY_SIZE(vmstat_text))
                return NULL;
        stat_items_size = NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long) +
+                         NR_VM_NODE_STAT_ITEMS * sizeof(unsigned long) +
                          NR_VM_WRITEBACK_STAT_ITEMS * sizeof(unsigned long);
 
 #ifdef CONFIG_VM_EVENT_COUNTERS
@@ -1301,6 +1564,10 @@ static void *vmstat_start(struct seq_file *m, loff_t *pos)
                v[i] = global_page_state(i);
        v += NR_VM_ZONE_STAT_ITEMS;
 
+       for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
+               v[i] = global_node_page_state(i);
+       v += NR_VM_NODE_STAT_ITEMS;
+
        global_dirty_limits(v + NR_DIRTY_BG_THRESHOLD,
                            v + NR_DIRTY_THRESHOLD);
        v += NR_VM_WRITEBACK_STAT_ITEMS;
@@ -1325,7 +1592,6 @@ static int vmstat_show(struct seq_file *m, void *arg)
 {
        unsigned long *l = arg;
        unsigned long off = l - (unsigned long *)m->private;
-
        seq_printf(m, "%s %lu\n", vmstat_text[off], *l);
        return 0;
 }
@@ -1390,13 +1656,12 @@ int vmstat_refresh(struct ctl_table *table, int write,
        if (err)
                return err;
        for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) {
-               val = atomic_long_read(&vm_stat[i]);
+               val = atomic_long_read(&vm_zone_stat[i]);
                if (val < 0) {
                        switch (i) {
-                       case NR_ALLOC_BATCH:
                        case NR_PAGES_SCANNED:
                                /*
-                                * These are often seen to go negative in
+                                * This is often seen to go negative in
                                 * recent kernels, but not to go permanently
                                 * negative.  Whilst it would be nicer not to
                                 * have exceptions, rooting them out would be
index 5772775..69551cf 100644 (file)
@@ -16,7 +16,7 @@
 /*
  *             Double CLOCK lists
  *
- * Per zone, two clock lists are maintained for file pages: the
+ * Per node, two clock lists are maintained for file pages: the
  * inactive and the active list.  Freshly faulted pages start out at
  * the head of the inactive list and page reclaim scans pages from the
  * tail.  Pages that are accessed multiple times on the inactive list
  *
  *             Implementation
  *
- * For each zone's file LRU lists, a counter for inactive evictions
- * and activations is maintained (zone->inactive_age).
+ * For each node's file LRU lists, a counter for inactive evictions
+ * and activations is maintained (node->inactive_age).
  *
  * On eviction, a snapshot of this counter (along with some bits to
- * identify the zone) is stored in the now empty page cache radix tree
+ * identify the node) is stored in the now empty page cache radix tree
  * slot of the evicted page.  This is called a shadow entry.
  *
  * On cache misses for which there are shadow entries, an eligible
  */
 
 #define EVICTION_SHIFT (RADIX_TREE_EXCEPTIONAL_ENTRY + \
-                        ZONES_SHIFT + NODES_SHIFT +    \
+                        NODES_SHIFT +  \
                         MEM_CGROUP_ID_SHIFT)
 #define EVICTION_MASK  (~0UL >> EVICTION_SHIFT)
 
  */
 static unsigned int bucket_order __read_mostly;
 
-static void *pack_shadow(int memcgid, struct zone *zone, unsigned long eviction)
+static void *pack_shadow(int memcgid, pg_data_t *pgdat, unsigned long eviction)
 {
        eviction >>= bucket_order;
        eviction = (eviction << MEM_CGROUP_ID_SHIFT) | memcgid;
-       eviction = (eviction << NODES_SHIFT) | zone_to_nid(zone);
-       eviction = (eviction << ZONES_SHIFT) | zone_idx(zone);
+       eviction = (eviction << NODES_SHIFT) | pgdat->node_id;
        eviction = (eviction << RADIX_TREE_EXCEPTIONAL_SHIFT);
 
        return (void *)(eviction | RADIX_TREE_EXCEPTIONAL_ENTRY);
 }
 
-static void unpack_shadow(void *shadow, int *memcgidp, struct zone **zonep,
+static void unpack_shadow(void *shadow, int *memcgidp, pg_data_t **pgdat,
                          unsigned long *evictionp)
 {
        unsigned long entry = (unsigned long)shadow;
-       int memcgid, nid, zid;
+       int memcgid, nid;
 
        entry >>= RADIX_TREE_EXCEPTIONAL_SHIFT;
-       zid = entry & ((1UL << ZONES_SHIFT) - 1);
-       entry >>= ZONES_SHIFT;
        nid = entry & ((1UL << NODES_SHIFT) - 1);
        entry >>= NODES_SHIFT;
        memcgid = entry & ((1UL << MEM_CGROUP_ID_SHIFT) - 1);
        entry >>= MEM_CGROUP_ID_SHIFT;
 
        *memcgidp = memcgid;
-       *zonep = NODE_DATA(nid)->node_zones + zid;
+       *pgdat = NODE_DATA(nid);
        *evictionp = entry << bucket_order;
 }
 
@@ -208,7 +205,7 @@ static void unpack_shadow(void *shadow, int *memcgidp, struct zone **zonep,
 void *workingset_eviction(struct address_space *mapping, struct page *page)
 {
        struct mem_cgroup *memcg = page_memcg(page);
-       struct zone *zone = page_zone(page);
+       struct pglist_data *pgdat = page_pgdat(page);
        int memcgid = mem_cgroup_id(memcg);
        unsigned long eviction;
        struct lruvec *lruvec;
@@ -218,9 +215,9 @@ void *workingset_eviction(struct address_space *mapping, struct page *page)
        VM_BUG_ON_PAGE(page_count(page), page);
        VM_BUG_ON_PAGE(!PageLocked(page), page);
 
-       lruvec = mem_cgroup_zone_lruvec(zone, memcg);
+       lruvec = mem_cgroup_lruvec(pgdat, memcg);
        eviction = atomic_long_inc_return(&lruvec->inactive_age);
-       return pack_shadow(memcgid, zone, eviction);
+       return pack_shadow(memcgid, pgdat, eviction);
 }
 
 /**
@@ -228,7 +225,7 @@ void *workingset_eviction(struct address_space *mapping, struct page *page)
  * @shadow: shadow entry of the evicted page
  *
  * Calculates and evaluates the refault distance of the previously
- * evicted page in the context of the zone it was allocated in.
+ * evicted page in the context of the node it was allocated in.
  *
  * Returns %true if the page should be activated, %false otherwise.
  */
@@ -240,10 +237,10 @@ bool workingset_refault(void *shadow)
        unsigned long eviction;
        struct lruvec *lruvec;
        unsigned long refault;
-       struct zone *zone;
+       struct pglist_data *pgdat;
        int memcgid;
 
-       unpack_shadow(shadow, &memcgid, &zone, &eviction);
+       unpack_shadow(shadow, &memcgid, &pgdat, &eviction);
 
        rcu_read_lock();
        /*
@@ -267,7 +264,7 @@ bool workingset_refault(void *shadow)
                rcu_read_unlock();
                return false;
        }
-       lruvec = mem_cgroup_zone_lruvec(zone, memcg);
+       lruvec = mem_cgroup_lruvec(pgdat, memcg);
        refault = atomic_long_read(&lruvec->inactive_age);
        active_file = lruvec_lru_size(lruvec, LRU_ACTIVE_FILE);
        rcu_read_unlock();
@@ -290,10 +287,10 @@ bool workingset_refault(void *shadow)
         */
        refault_distance = (refault - eviction) & EVICTION_MASK;
 
-       inc_zone_state(zone, WORKINGSET_REFAULT);
+       inc_node_state(pgdat, WORKINGSET_REFAULT);
 
        if (refault_distance <= active_file) {
-               inc_zone_state(zone, WORKINGSET_ACTIVATE);
+               inc_node_state(pgdat, WORKINGSET_ACTIVATE);
                return true;
        }
        return false;
@@ -305,9 +302,10 @@ bool workingset_refault(void *shadow)
  */
 void workingset_activation(struct page *page)
 {
+       struct mem_cgroup *memcg;
        struct lruvec *lruvec;
 
-       lock_page_memcg(page);
+       rcu_read_lock();
        /*
         * Filter non-memcg pages here, e.g. unmap can call
         * mark_page_accessed() on VDSO pages.
@@ -315,12 +313,13 @@ void workingset_activation(struct page *page)
         * XXX: See workingset_refault() - this should return
         * root_mem_cgroup even for !CONFIG_MEMCG.
         */
-       if (!mem_cgroup_disabled() && !page_memcg(page))
+       memcg = page_memcg_rcu(page);
+       if (!mem_cgroup_disabled() && !memcg)
                goto out;
-       lruvec = mem_cgroup_zone_lruvec(page_zone(page), page_memcg(page));
+       lruvec = mem_cgroup_lruvec(page_pgdat(page), memcg);
        atomic_long_inc(&lruvec->inactive_age);
 out:
-       unlock_page_memcg(page);
+       rcu_read_unlock();
 }
 
 /*
@@ -349,12 +348,13 @@ static unsigned long count_shadow_nodes(struct shrinker *shrinker,
        shadow_nodes = list_lru_shrink_count(&workingset_shadow_nodes, sc);
        local_irq_enable();
 
-       if (memcg_kmem_enabled())
+       if (memcg_kmem_enabled()) {
                pages = mem_cgroup_node_nr_lru_pages(sc->memcg, sc->nid,
                                                     LRU_ALL_FILE);
-       else
-               pages = node_page_state(sc->nid, NR_ACTIVE_FILE) +
-                       node_page_state(sc->nid, NR_INACTIVE_FILE);
+       } else {
+               pages = node_page_state(NODE_DATA(sc->nid), NR_ACTIVE_FILE) +
+                       node_page_state(NODE_DATA(sc->nid), NR_INACTIVE_FILE);
+       }
 
        /*
         * Active cache pages are limited to 50% of memory, and shadow
@@ -433,7 +433,7 @@ static enum lru_status shadow_lru_isolate(struct list_head *item,
                }
        }
        BUG_ON(node->count);
-       inc_zone_state(page_zone(virt_to_page(node)), WORKINGSET_NODERECLAIM);
+       inc_node_state(page_pgdat(virt_to_page(node)), WORKINGSET_NODERECLAIM);
        if (!__radix_tree_delete_node(&mapping->page_tree, node))
                BUG();
 
index 04176de..b0bc023 100644 (file)
@@ -20,6 +20,7 @@
  *     page->freelist(index): links together all component pages of a zspage
  *             For the huge page, this is always 0, so we use this field
  *             to store handle.
+ *     page->units: first object offset in a subpage of zspage
  *
  * Usage of struct page flags:
  *     PG_private: identifies the first component page
  */
 #define ZS_SIZE_CLASS_DELTA    (PAGE_SIZE >> CLASS_BITS)
 
-/*
- * We do not maintain any list for completely empty or full pages
- */
 enum fullness_group {
        ZS_EMPTY,
        ZS_ALMOST_EMPTY,
@@ -467,11 +465,6 @@ static struct zpool_driver zs_zpool_driver = {
 MODULE_ALIAS("zpool-zsmalloc");
 #endif /* CONFIG_ZPOOL */
 
-static unsigned int get_maxobj_per_zspage(int size, int pages_per_zspage)
-{
-       return pages_per_zspage * PAGE_SIZE / size;
-}
-
 /* per-cpu VM mapping areas for zspage accesses that cross page boundaries */
 static DEFINE_PER_CPU(struct mapping_area, zs_map_area);
 
@@ -635,8 +628,7 @@ static int zs_stats_size_show(struct seq_file *s, void *v)
                freeable = zs_can_compact(class);
                spin_unlock(&class->lock);
 
-               objs_per_zspage = get_maxobj_per_zspage(class->size,
-                               class->pages_per_zspage);
+               objs_per_zspage = class->objs_per_zspage;
                pages_used = obj_allocated / objs_per_zspage *
                                class->pages_per_zspage;
 
@@ -945,8 +937,8 @@ static void unpin_tag(unsigned long handle)
 static void reset_page(struct page *page)
 {
        __ClearPageMovable(page);
-       clear_bit(PG_private, &page->flags);
-       clear_bit(PG_private_2, &page->flags);
+       ClearPagePrivate(page);
+       ClearPagePrivate2(page);
        set_page_private(page, 0);
        page_mapcount_reset(page);
        ClearPageHugeObject(page);
@@ -1014,8 +1006,7 @@ static void __free_zspage(struct zs_pool *pool, struct size_class *class,
 
        cache_free_zspage(pool, zspage);
 
-       zs_stat_dec(class, OBJ_ALLOCATED, get_maxobj_per_zspage(
-                       class->size, class->pages_per_zspage));
+       zs_stat_dec(class, OBJ_ALLOCATED, class->objs_per_zspage);
        atomic_long_sub(class->pages_per_zspage,
                                        &pool->pages_allocated);
 }
@@ -1350,7 +1341,7 @@ static void zs_unregister_cpu_notifier(void)
        cpu_notifier_register_done();
 }
 
-static void init_zs_size_classes(void)
+static void __init init_zs_size_classes(void)
 {
        int nr;
 
@@ -1361,16 +1352,14 @@ static void init_zs_size_classes(void)
        zs_size_classes = nr;
 }
 
-static bool can_merge(struct size_class *prev, int size, int pages_per_zspage)
+static bool can_merge(struct size_class *prev, int pages_per_zspage,
+                                       int objs_per_zspage)
 {
-       if (prev->pages_per_zspage != pages_per_zspage)
-               return false;
+       if (prev->pages_per_zspage == pages_per_zspage &&
+               prev->objs_per_zspage == objs_per_zspage)
+               return true;
 
-       if (get_maxobj_per_zspage(prev->size, prev->pages_per_zspage)
-               != get_maxobj_per_zspage(size, pages_per_zspage))
-               return false;
-
-       return true;
+       return false;
 }
 
 static bool zspage_full(struct size_class *class, struct zspage *zspage)
@@ -1541,6 +1530,7 @@ static unsigned long obj_malloc(struct size_class *class,
  * zs_malloc - Allocate block of given size from pool.
  * @pool: pool to allocate from
  * @size: size of block to allocate
+ * @gfp: gfp flags when allocating object
  *
  * On success, handle to the allocated object is returned,
  * otherwise 0.
@@ -1592,8 +1582,7 @@ unsigned long zs_malloc(struct zs_pool *pool, size_t size, gfp_t gfp)
        record_obj(handle, obj);
        atomic_long_add(class->pages_per_zspage,
                                &pool->pages_allocated);
-       zs_stat_inc(class, OBJ_ALLOCATED, get_maxobj_per_zspage(
-                       class->size, class->pages_per_zspage));
+       zs_stat_inc(class, OBJ_ALLOCATED, class->objs_per_zspage);
 
        /* We completely set up zspage so mark them as movable */
        SetZsPageMovable(pool, zspage);
@@ -1741,10 +1730,11 @@ static void zs_object_copy(struct size_class *class, unsigned long dst,
  * return handle.
  */
 static unsigned long find_alloced_obj(struct size_class *class,
-                                       struct page *page, int index)
+                                       struct page *page, int *obj_idx)
 {
        unsigned long head;
        int offset = 0;
+       int index = *obj_idx;
        unsigned long handle = 0;
        void *addr = kmap_atomic(page);
 
@@ -1765,6 +1755,9 @@ static unsigned long find_alloced_obj(struct size_class *class,
        }
 
        kunmap_atomic(addr);
+
+       *obj_idx = index;
+
        return handle;
 }
 
@@ -1776,7 +1769,7 @@ struct zs_compact_control {
        struct page *d_page;
         /* Starting object index within @s_page which used for live object
          * in the subpage. */
-       int index;
+       int obj_idx;
 };
 
 static int migrate_zspage(struct zs_pool *pool, struct size_class *class,
@@ -1786,16 +1779,16 @@ static int migrate_zspage(struct zs_pool *pool, struct size_class *class,
        unsigned long handle;
        struct page *s_page = cc->s_page;
        struct page *d_page = cc->d_page;
-       unsigned long index = cc->index;
+       int obj_idx = cc->obj_idx;
        int ret = 0;
 
        while (1) {
-               handle = find_alloced_obj(class, s_page, index);
+               handle = find_alloced_obj(class, s_page, &obj_idx);
                if (!handle) {
                        s_page = get_next_page(s_page);
                        if (!s_page)
                                break;
-                       index = 0;
+                       obj_idx = 0;
                        continue;
                }
 
@@ -1809,7 +1802,7 @@ static int migrate_zspage(struct zs_pool *pool, struct size_class *class,
                used_obj = handle_to_obj(handle);
                free_obj = obj_malloc(class, get_zspage(d_page), handle);
                zs_object_copy(class, free_obj, used_obj);
-               index++;
+               obj_idx++;
                /*
                 * record_obj updates handle's value to free_obj and it will
                 * invalidate lock bit(ie, HANDLE_PIN_BIT) of handle, which
@@ -1824,7 +1817,7 @@ static int migrate_zspage(struct zs_pool *pool, struct size_class *class,
 
        /* Remember last position in this iteration */
        cc->s_page = s_page;
-       cc->index = index;
+       cc->obj_idx = obj_idx;
 
        return ret;
 }
@@ -2181,8 +2174,7 @@ static int zs_register_migration(struct zs_pool *pool)
 static void zs_unregister_migration(struct zs_pool *pool)
 {
        flush_work(&pool->free_work);
-       if (pool->inode)
-               iput(pool->inode);
+       iput(pool->inode);
 }
 
 /*
@@ -2261,8 +2253,7 @@ static unsigned long zs_can_compact(struct size_class *class)
                return 0;
 
        obj_wasted = obj_allocated - obj_used;
-       obj_wasted /= get_maxobj_per_zspage(class->size,
-                       class->pages_per_zspage);
+       obj_wasted /= class->objs_per_zspage;
 
        return obj_wasted * class->pages_per_zspage;
 }
@@ -2279,7 +2270,7 @@ static void __zs_compact(struct zs_pool *pool, struct size_class *class)
                if (!zs_can_compact(class))
                        break;
 
-               cc.index = 0;
+               cc.obj_idx = 0;
                cc.s_page = get_first_page(src_zspage);
 
                while ((dst_zspage = isolate_zspage(class, false))) {
@@ -2398,7 +2389,7 @@ static int zs_register_shrinker(struct zs_pool *pool)
 
 /**
  * zs_create_pool - Creates an allocation pool to work from.
- * @flags: allocation flags used to allocate pool metadata
+ * @name: pool name to be created
  *
  * This function must be called before anything when using
  * the zsmalloc allocator.
@@ -2438,6 +2429,7 @@ struct zs_pool *zs_create_pool(const char *name)
        for (i = zs_size_classes - 1; i >= 0; i--) {
                int size;
                int pages_per_zspage;
+               int objs_per_zspage;
                struct size_class *class;
                int fullness = 0;
 
@@ -2445,6 +2437,7 @@ struct zs_pool *zs_create_pool(const char *name)
                if (size > ZS_MAX_ALLOC_SIZE)
                        size = ZS_MAX_ALLOC_SIZE;
                pages_per_zspage = get_pages_per_zspage(size);
+               objs_per_zspage = pages_per_zspage * PAGE_SIZE / size;
 
                /*
                 * size_class is used for normal zsmalloc operation such
@@ -2456,7 +2449,7 @@ struct zs_pool *zs_create_pool(const char *name)
                 * previous size_class if possible.
                 */
                if (prev_class) {
-                       if (can_merge(prev_class, size, pages_per_zspage)) {
+                       if (can_merge(prev_class, pages_per_zspage, objs_per_zspage)) {
                                pool->size_class[i] = prev_class;
                                continue;
                        }
@@ -2469,8 +2462,7 @@ struct zs_pool *zs_create_pool(const char *name)
                class->size = size;
                class->index = i;
                class->pages_per_zspage = pages_per_zspage;
-               class->objs_per_zspage = class->pages_per_zspage *
-                                               PAGE_SIZE / class->size;
+               class->objs_per_zspage = objs_per_zspage;
                spin_lock_init(&class->lock);
                pool->size_class[i] = class;
                for (fullness = ZS_EMPTY; fullness < NR_ZS_FULLNESS;
index 2a9c39f..4ce07dc 100644 (file)
@@ -198,7 +198,7 @@ static inline void dev_base_seq_inc(struct net *net)
 
 static inline struct hlist_head *dev_name_hash(struct net *net, const char *name)
 {
-       unsigned int hash = full_name_hash(name, strnlen(name, IFNAMSIZ));
+       unsigned int hash = full_name_hash(net, name, strnlen(name, IFNAMSIZ));
 
        return &net->dev_name_head[hash_32(hash, NETDEV_HASHBITS)];
 }
index 4904ced..24a0836 100755 (executable)
@@ -313,7 +313,6 @@ our $Sparse = qr{
                        __kernel|
                        __force|
                        __iomem|
-                       __pmem|
                        __must_check|
                        __init_refok|
                        __kprobes|
index 28414b0..e3df905 100644 (file)
@@ -186,24 +186,21 @@ EXPORT_SYMBOL_GPL(securityfs_create_dir);
  */
 void securityfs_remove(struct dentry *dentry)
 {
-       struct dentry *parent;
+       struct inode *dir;
 
        if (!dentry || IS_ERR(dentry))
                return;
 
-       parent = dentry->d_parent;
-       if (!parent || d_really_is_negative(parent))
-               return;
-
-       inode_lock(d_inode(parent));
+       dir = d_inode(dentry->d_parent);
+       inode_lock(dir);
        if (simple_positive(dentry)) {
                if (d_is_dir(dentry))
-                       simple_rmdir(d_inode(parent), dentry);
+                       simple_rmdir(dir, dentry);
                else
-                       simple_unlink(d_inode(parent), dentry);
+                       simple_unlink(dir, dentry);
                dput(dentry);
        }
-       inode_unlock(d_inode(parent));
+       inode_unlock(dir);
        simple_release_fs(&mount, &mount_count);
 }
 EXPORT_SYMBOL_GPL(securityfs_remove);
index a283f9e..23e5808 100644 (file)
@@ -413,7 +413,7 @@ void smk_insert_entry(struct smack_known *skp)
        unsigned int hash;
        struct hlist_head *head;
 
-       hash = full_name_hash(skp->smk_known, strlen(skp->smk_known));
+       hash = full_name_hash(NULL, skp->smk_known, strlen(skp->smk_known));
        head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
 
        hlist_add_head_rcu(&skp->smk_hashed, head);
@@ -433,7 +433,7 @@ struct smack_known *smk_find_entry(const char *string)
        struct hlist_head *head;
        struct smack_known *skp;
 
-       hash = full_name_hash(string, strlen(string));
+       hash = full_name_hash(NULL, string, strlen(string));
        head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
 
        hlist_for_each_entry_rcu(skp, head, smk_hashed)
index 0e99571..1598b55 100644 (file)
@@ -154,7 +154,7 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name)
        if (!name)
                return NULL;
        len = strlen(name) + 1;
-       hash = full_name_hash((const unsigned char *) name, len - 1);
+       hash = full_name_hash(NULL, (const unsigned char *) name, len - 1);
        head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)];
        if (mutex_lock_interruptible(&tomoyo_policy_lock))
                return NULL;
index b974a69..5fe3679 100644 (file)
@@ -666,7 +666,7 @@ void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
        ptr->const_len = tomoyo_const_part_length(name);
        ptr->is_dir = len && (name[len - 1] == '/');
        ptr->is_patterned = (ptr->const_len < len);
-       ptr->hash = full_name_hash(name, len);
+       ptr->hash = full_name_hash(NULL, name, len);
 }
 
 /**
index 6da7229..368343f 100644 (file)
@@ -32,6 +32,4 @@
 #define MAX9877_BYPASS                 (1 << 6)
 #define MAX9877_SHDN                   (1 << 7)
 
-extern int max9877_add_controls(struct snd_soc_codec *codec);
-
 #endif
index d388de7..28632ee 100644 (file)
@@ -947,7 +947,7 @@ GrpTable: Grp15
 4: XSAVE
 5: XRSTOR | lfence (11B)
 6: XSAVEOPT | clwb (66) | mfence (11B)
-7: clflush | clflushopt (66) | sfence (11B) | pcommit (66),(11B)
+7: clflush | clflushopt (66) | sfence (11B)
 EndTable
 
 GrpTable: Grp16
index 3918dd5..0f196ee 100644 (file)
 "0f c7 1d 78 56 34 12 \txrstors 0x12345678",},
 {{0x0f, 0xc7, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "",
 "0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%eax,%ecx,8)",},
-{{0x66, 0x0f, 0xae, 0xf8, }, 4, 0, "", "",
-"66 0f ae f8          \tpcommit ",},
index 9c8c61e..af25bc8 100644 (file)
 "0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%rax,%rcx,8)",},
 {{0x41, 0x0f, 0xc7, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "",
 "41 0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%r8,%rcx,8)",},
-{{0x66, 0x0f, 0xae, 0xf8, }, 4, 0, "", "",
-"66 0f ae f8          \tpcommit ",},
index 76e0ec3..979487d 100644 (file)
@@ -2655,10 +2655,6 @@ int main(void)
 
 #endif /* #ifndef __x86_64__ */
 
-       /* pcommit */
-
-       asm volatile("pcommit");
-
        /* Following line is a marker for the awk script - do not change */
        asm volatile("rdtsc"); /* Stop here */
 
index b1d491c..fdde1bd 100644 (file)
@@ -608,6 +608,7 @@ static const struct {
        const char *compact;
 } gfp_compact_table[] = {
        { "GFP_TRANSHUGE",              "THP" },
+       { "GFP_TRANSHUGE_LIGHT",        "THL" },
        { "GFP_HIGHUSER_MOVABLE",       "HUM" },
        { "GFP_HIGHUSER",               "HU" },
        { "GFP_USER",                   "U" },
index ec378cd..767be7c 100644 (file)
@@ -1012,7 +1012,7 @@ GrpTable: Grp15
 4: XSAVE
 5: XRSTOR | lfence (11B)
 6: XSAVEOPT | clwb (66) | mfence (11B)
-7: clflush | clflushopt (66) | sfence (11B) | pcommit (66),(11B)
+7: clflush | clflushopt (66) | sfence (11B)
 EndTable
 
 GrpTable: Grp16
index 7859856..ad6dd05 100644 (file)
@@ -11,12 +11,14 @@ ldflags-y += --wrap=__devm_release_region
 ldflags-y += --wrap=__request_region
 ldflags-y += --wrap=__release_region
 ldflags-y += --wrap=devm_memremap_pages
-ldflags-y += --wrap=phys_to_pfn_t
+ldflags-y += --wrap=insert_resource
+ldflags-y += --wrap=remove_resource
 
 DRIVERS := ../../../drivers
 NVDIMM_SRC := $(DRIVERS)/nvdimm
-ACPI_SRC := $(DRIVERS)/acpi
+ACPI_SRC := $(DRIVERS)/acpi/nfit
 DAX_SRC := $(DRIVERS)/dax
+ccflags-y := -I$(src)/$(NVDIMM_SRC)/
 
 obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o
 obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o
@@ -27,10 +29,12 @@ obj-$(CONFIG_ACPI_NFIT) += nfit.o
 obj-$(CONFIG_DEV_DAX) += dax.o
 obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o
 
-nfit-y := $(ACPI_SRC)/nfit.o
+nfit-y := $(ACPI_SRC)/core.o
+nfit-$(CONFIG_X86_MCE) += $(ACPI_SRC)/mce.o
 nfit-y += config_check.o
 
 nd_pmem-y := $(NVDIMM_SRC)/pmem.o
+nd_pmem-y += pmem-dax.o
 nd_pmem-y += config_check.o
 
 nd_btt-y := $(NVDIMM_SRC)/btt.o
index adf18bf..878daf3 100644 (file)
@@ -10,6 +10,7 @@ void check(void)
        BUILD_BUG_ON(!IS_MODULE(CONFIG_LIBNVDIMM));
        BUILD_BUG_ON(!IS_MODULE(CONFIG_BLK_DEV_PMEM));
        BUILD_BUG_ON(!IS_MODULE(CONFIG_ND_BTT));
+       BUILD_BUG_ON(!IS_MODULE(CONFIG_ND_PFN));
        BUILD_BUG_ON(!IS_MODULE(CONFIG_ND_BLK));
        BUILD_BUG_ON(!IS_MODULE(CONFIG_ACPI_NFIT));
        BUILD_BUG_ON(!IS_MODULE(CONFIG_DEV_DAX));
diff --git a/tools/testing/nvdimm/pmem-dax.c b/tools/testing/nvdimm/pmem-dax.c
new file mode 100644 (file)
index 0000000..c9b8c48
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2014-2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+#include "test/nfit_test.h"
+#include <linux/blkdev.h>
+#include <pmem.h>
+#include <nd.h>
+
+long pmem_direct_access(struct block_device *bdev, sector_t sector,
+               void **kaddr, pfn_t *pfn, long size)
+{
+       struct pmem_device *pmem = bdev->bd_queue->queuedata;
+       resource_size_t offset = sector * 512 + pmem->data_offset;
+
+       if (unlikely(is_bad_pmem(&pmem->bb, sector, size)))
+               return -EIO;
+
+       /*
+        * Limit dax to a single page at a time given vmalloc()-backed
+        * in the nfit_test case.
+        */
+       if (get_nfit_res(pmem->phys_addr + offset)) {
+               struct page *page;
+
+               *kaddr = pmem->virt_addr + offset;
+               page = vmalloc_to_page(pmem->virt_addr + offset);
+               *pfn = page_to_pfn_t(page);
+               dev_dbg_ratelimited(disk_to_dev(bdev->bd_disk)->parent,
+                               "%s: sector: %#llx pfn: %#lx\n", __func__,
+                               (unsigned long long) sector, page_to_pfn(page));
+
+               return PAGE_SIZE;
+       }
+
+       *kaddr = pmem->virt_addr + offset;
+       *pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags);
+
+       /*
+        * If badblocks are present, limit known good range to the
+        * requested range.
+        */
+       if (unlikely(pmem->bb.count))
+               return size;
+       return pmem->size - pmem->pfn_pad - offset;
+}
index 9241064..d32f25b 100644 (file)
@@ -1,5 +1,5 @@
 ccflags-y := -I$(src)/../../../../drivers/nvdimm/
-ccflags-y += -I$(src)/../../../../drivers/acpi/
+ccflags-y += -I$(src)/../../../../drivers/acpi/nfit/
 
 obj-m += nfit_test.o
 obj-m += nfit_test_iomap.o
index c842095..c29f8dc 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  */
+#include <linux/memremap.h>
 #include <linux/rculist.h>
 #include <linux/export.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
 #include <linux/types.h>
+#include <linux/pfn_t.h>
 #include <linux/io.h>
 #include <linux/mm.h>
 #include "nfit_test.h"
@@ -52,7 +54,7 @@ static struct nfit_test_resource *__get_nfit_res(resource_size_t resource)
        return NULL;
 }
 
-static struct nfit_test_resource *get_nfit_res(resource_size_t resource)
+struct nfit_test_resource *get_nfit_res(resource_size_t resource)
 {
        struct nfit_test_resource *res;
 
@@ -62,6 +64,7 @@ static struct nfit_test_resource *get_nfit_res(resource_size_t resource)
 
        return res;
 }
+EXPORT_SYMBOL(get_nfit_res);
 
 void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size,
                void __iomem *(*fallback_fn)(resource_size_t, unsigned long))
@@ -97,10 +100,6 @@ void *__wrap_devm_memremap(struct device *dev, resource_size_t offset,
 }
 EXPORT_SYMBOL(__wrap_devm_memremap);
 
-#ifdef __HAVE_ARCH_PTE_DEVMAP
-#include <linux/memremap.h>
-#include <linux/pfn_t.h>
-
 void *__wrap_devm_memremap_pages(struct device *dev, struct resource *res,
                struct percpu_ref *ref, struct vmem_altmap *altmap)
 {
@@ -122,19 +121,6 @@ pfn_t __wrap_phys_to_pfn_t(phys_addr_t addr, unsigned long flags)
         return phys_to_pfn_t(addr, flags);
 }
 EXPORT_SYMBOL(__wrap_phys_to_pfn_t);
-#else
-/* to be removed post 4.5-rc1 */
-void *__wrap_devm_memremap_pages(struct device *dev, struct resource *res)
-{
-       resource_size_t offset = res->start;
-       struct nfit_test_resource *nfit_res = get_nfit_res(offset);
-
-       if (nfit_res)
-               return nfit_res->buf + offset - nfit_res->res->start;
-       return devm_memremap_pages(dev, res);
-}
-EXPORT_SYMBOL(__wrap_devm_memremap_pages);
-#endif
 
 void *__wrap_memremap(resource_size_t offset, size_t size,
                unsigned long flags)
@@ -229,6 +215,22 @@ struct resource *__wrap___request_region(struct resource *parent,
 }
 EXPORT_SYMBOL(__wrap___request_region);
 
+int __wrap_insert_resource(struct resource *parent, struct resource *res)
+{
+       if (get_nfit_res(res->start))
+               return 0;
+       return insert_resource(parent, res);
+}
+EXPORT_SYMBOL(__wrap_insert_resource);
+
+int __wrap_remove_resource(struct resource *res)
+{
+       if (get_nfit_res(res->start))
+               return 0;
+       return remove_resource(res);
+}
+EXPORT_SYMBOL(__wrap_remove_resource);
+
 struct resource *__wrap___devm_request_region(struct device *dev,
                struct resource *parent, resource_size_t start,
                resource_size_t n, const char *name)
index c919866..5404efa 100644 (file)
 enum {
        NUM_PM  = 3,
        NUM_DCR = 5,
+       NUM_HINTS = 8,
        NUM_BDW = NUM_DCR,
        NUM_SPA = NUM_PM + NUM_DCR + NUM_BDW,
        NUM_MEM = NUM_DCR + NUM_BDW + 2 /* spa0 iset */ + 4 /* spa1 iset */,
        DIMM_SIZE = SZ_32M,
        LABEL_SIZE = SZ_128K,
+       SPA_VCD_SIZE = SZ_4M,
        SPA0_SIZE = DIMM_SIZE,
        SPA1_SIZE = DIMM_SIZE*2,
        SPA2_SIZE = DIMM_SIZE,
@@ -470,11 +472,7 @@ static void release_nfit_res(void *data)
        list_del(&nfit_res->list);
        spin_unlock(&nfit_test_lock);
 
-       if (is_vmalloc_addr(nfit_res->buf))
-               vfree(nfit_res->buf);
-       else
-               dma_free_coherent(nfit_res->dev, resource_size(res),
-                               nfit_res->buf, res->start);
+       vfree(nfit_res->buf);
        kfree(res);
        kfree(nfit_res);
 }
@@ -507,9 +505,7 @@ static void *__test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma,
 
        return nfit_res->buf;
  err:
-       if (buf && !is_vmalloc_addr(buf))
-               dma_free_coherent(dev, size, buf, *dma);
-       else if (buf)
+       if (buf)
                vfree(buf);
        kfree(res);
        kfree(nfit_res);
@@ -524,15 +520,6 @@ static void *test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma)
        return __test_alloc(t, size, dma, buf);
 }
 
-static void *test_alloc_coherent(struct nfit_test *t, size_t size,
-               dma_addr_t *dma)
-{
-       struct device *dev = &t->pdev.dev;
-       void *buf = dma_alloc_coherent(dev, size, dma, GFP_KERNEL);
-
-       return __test_alloc(t, size, dma, buf);
-}
-
 static struct nfit_test_resource *nfit_test_lookup(resource_size_t addr)
 {
        int i;
@@ -584,7 +571,8 @@ static int nfit_test0_alloc(struct nfit_test *t)
                        + offsetof(struct acpi_nfit_control_region,
                                        window_size) * NUM_DCR
                        + sizeof(struct acpi_nfit_data_region) * NUM_BDW
-                       + sizeof(struct acpi_nfit_flush_address) * NUM_DCR;
+                       + (sizeof(struct acpi_nfit_flush_address)
+                                       + sizeof(u64) * NUM_HINTS) * NUM_DCR;
        int i;
 
        t->nfit_buf = test_alloc(t, nfit_size, &t->nfit_dma);
@@ -592,15 +580,15 @@ static int nfit_test0_alloc(struct nfit_test *t)
                return -ENOMEM;
        t->nfit_size = nfit_size;
 
-       t->spa_set[0] = test_alloc_coherent(t, SPA0_SIZE, &t->spa_set_dma[0]);
+       t->spa_set[0] = test_alloc(t, SPA0_SIZE, &t->spa_set_dma[0]);
        if (!t->spa_set[0])
                return -ENOMEM;
 
-       t->spa_set[1] = test_alloc_coherent(t, SPA1_SIZE, &t->spa_set_dma[1]);
+       t->spa_set[1] = test_alloc(t, SPA1_SIZE, &t->spa_set_dma[1]);
        if (!t->spa_set[1])
                return -ENOMEM;
 
-       t->spa_set[2] = test_alloc_coherent(t, SPA0_SIZE, &t->spa_set_dma[2]);
+       t->spa_set[2] = test_alloc(t, SPA0_SIZE, &t->spa_set_dma[2]);
        if (!t->spa_set[2])
                return -ENOMEM;
 
@@ -614,7 +602,8 @@ static int nfit_test0_alloc(struct nfit_test *t)
                        return -ENOMEM;
                sprintf(t->label[i], "label%d", i);
 
-               t->flush[i] = test_alloc(t, 8, &t->flush_dma[i]);
+               t->flush[i] = test_alloc(t, sizeof(u64) * NUM_HINTS,
+                               &t->flush_dma[i]);
                if (!t->flush[i])
                        return -ENOMEM;
        }
@@ -630,7 +619,7 @@ static int nfit_test0_alloc(struct nfit_test *t)
 
 static int nfit_test1_alloc(struct nfit_test *t)
 {
-       size_t nfit_size = sizeof(struct acpi_nfit_system_address)
+       size_t nfit_size = sizeof(struct acpi_nfit_system_address) * 2
                + sizeof(struct acpi_nfit_memory_map)
                + offsetof(struct acpi_nfit_control_region, window_size);
 
@@ -639,15 +628,31 @@ static int nfit_test1_alloc(struct nfit_test *t)
                return -ENOMEM;
        t->nfit_size = nfit_size;
 
-       t->spa_set[0] = test_alloc_coherent(t, SPA2_SIZE, &t->spa_set_dma[0]);
+       t->spa_set[0] = test_alloc(t, SPA2_SIZE, &t->spa_set_dma[0]);
        if (!t->spa_set[0])
                return -ENOMEM;
 
+       t->spa_set[1] = test_alloc(t, SPA_VCD_SIZE, &t->spa_set_dma[1]);
+       if (!t->spa_set[1])
+               return -ENOMEM;
+
        return ars_state_init(&t->pdev.dev, &t->ars_state);
 }
 
+static void dcr_common_init(struct acpi_nfit_control_region *dcr)
+{
+       dcr->vendor_id = 0xabcd;
+       dcr->device_id = 0;
+       dcr->revision_id = 1;
+       dcr->valid_fields = 1;
+       dcr->manufacturing_location = 0xa;
+       dcr->manufacturing_date = cpu_to_be16(2016);
+}
+
 static void nfit_test0_setup(struct nfit_test *t)
 {
+       const int flush_hint_size = sizeof(struct acpi_nfit_flush_address)
+               + (sizeof(u64) * NUM_HINTS);
        struct acpi_nfit_desc *acpi_desc;
        struct acpi_nfit_memory_map *memdev;
        void *nfit_buf = t->nfit_buf;
@@ -655,7 +660,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        struct acpi_nfit_control_region *dcr;
        struct acpi_nfit_data_region *bdw;
        struct acpi_nfit_flush_address *flush;
-       unsigned int offset;
+       unsigned int offset, i;
 
        /*
         * spa0 (interleave first half of dimm0 and dimm1, note storage
@@ -972,9 +977,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION;
        dcr->header.length = sizeof(struct acpi_nfit_control_region);
        dcr->region_index = 0+1;
-       dcr->vendor_id = 0xabcd;
-       dcr->device_id = 0;
-       dcr->revision_id = 1;
+       dcr_common_init(dcr);
        dcr->serial_number = ~handle[0];
        dcr->code = NFIT_FIC_BLK;
        dcr->windows = 1;
@@ -989,9 +992,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION;
        dcr->header.length = sizeof(struct acpi_nfit_control_region);
        dcr->region_index = 1+1;
-       dcr->vendor_id = 0xabcd;
-       dcr->device_id = 0;
-       dcr->revision_id = 1;
+       dcr_common_init(dcr);
        dcr->serial_number = ~handle[1];
        dcr->code = NFIT_FIC_BLK;
        dcr->windows = 1;
@@ -1006,9 +1007,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION;
        dcr->header.length = sizeof(struct acpi_nfit_control_region);
        dcr->region_index = 2+1;
-       dcr->vendor_id = 0xabcd;
-       dcr->device_id = 0;
-       dcr->revision_id = 1;
+       dcr_common_init(dcr);
        dcr->serial_number = ~handle[2];
        dcr->code = NFIT_FIC_BLK;
        dcr->windows = 1;
@@ -1023,9 +1022,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION;
        dcr->header.length = sizeof(struct acpi_nfit_control_region);
        dcr->region_index = 3+1;
-       dcr->vendor_id = 0xabcd;
-       dcr->device_id = 0;
-       dcr->revision_id = 1;
+       dcr_common_init(dcr);
        dcr->serial_number = ~handle[3];
        dcr->code = NFIT_FIC_BLK;
        dcr->windows = 1;
@@ -1042,9 +1039,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        dcr->header.length = offsetof(struct acpi_nfit_control_region,
                        window_size);
        dcr->region_index = 4+1;
-       dcr->vendor_id = 0xabcd;
-       dcr->device_id = 0;
-       dcr->revision_id = 1;
+       dcr_common_init(dcr);
        dcr->serial_number = ~handle[0];
        dcr->code = NFIT_FIC_BYTEN;
        dcr->windows = 0;
@@ -1056,9 +1051,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        dcr->header.length = offsetof(struct acpi_nfit_control_region,
                        window_size);
        dcr->region_index = 5+1;
-       dcr->vendor_id = 0xabcd;
-       dcr->device_id = 0;
-       dcr->revision_id = 1;
+       dcr_common_init(dcr);
        dcr->serial_number = ~handle[1];
        dcr->code = NFIT_FIC_BYTEN;
        dcr->windows = 0;
@@ -1070,9 +1063,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        dcr->header.length = offsetof(struct acpi_nfit_control_region,
                        window_size);
        dcr->region_index = 6+1;
-       dcr->vendor_id = 0xabcd;
-       dcr->device_id = 0;
-       dcr->revision_id = 1;
+       dcr_common_init(dcr);
        dcr->serial_number = ~handle[2];
        dcr->code = NFIT_FIC_BYTEN;
        dcr->windows = 0;
@@ -1084,9 +1075,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        dcr->header.length = offsetof(struct acpi_nfit_control_region,
                        window_size);
        dcr->region_index = 7+1;
-       dcr->vendor_id = 0xabcd;
-       dcr->device_id = 0;
-       dcr->revision_id = 1;
+       dcr_common_init(dcr);
        dcr->serial_number = ~handle[3];
        dcr->code = NFIT_FIC_BYTEN;
        dcr->windows = 0;
@@ -1141,45 +1130,47 @@ static void nfit_test0_setup(struct nfit_test *t)
        /* flush0 (dimm0) */
        flush = nfit_buf + offset;
        flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS;
-       flush->header.length = sizeof(struct acpi_nfit_flush_address);
+       flush->header.length = flush_hint_size;
        flush->device_handle = handle[0];
-       flush->hint_count = 1;
-       flush->hint_address[0] = t->flush_dma[0];
+       flush->hint_count = NUM_HINTS;
+       for (i = 0; i < NUM_HINTS; i++)
+               flush->hint_address[i] = t->flush_dma[0] + i * sizeof(u64);
 
        /* flush1 (dimm1) */
-       flush = nfit_buf + offset + sizeof(struct acpi_nfit_flush_address) * 1;
+       flush = nfit_buf + offset + flush_hint_size * 1;
        flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS;
-       flush->header.length = sizeof(struct acpi_nfit_flush_address);
+       flush->header.length = flush_hint_size;
        flush->device_handle = handle[1];
-       flush->hint_count = 1;
-       flush->hint_address[0] = t->flush_dma[1];
+       flush->hint_count = NUM_HINTS;
+       for (i = 0; i < NUM_HINTS; i++)
+               flush->hint_address[i] = t->flush_dma[1] + i * sizeof(u64);
 
        /* flush2 (dimm2) */
-       flush = nfit_buf + offset + sizeof(struct acpi_nfit_flush_address) * 2;
+       flush = nfit_buf + offset + flush_hint_size  * 2;
        flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS;
-       flush->header.length = sizeof(struct acpi_nfit_flush_address);
+       flush->header.length = flush_hint_size;
        flush->device_handle = handle[2];
-       flush->hint_count = 1;
-       flush->hint_address[0] = t->flush_dma[2];
+       flush->hint_count = NUM_HINTS;
+       for (i = 0; i < NUM_HINTS; i++)
+               flush->hint_address[i] = t->flush_dma[2] + i * sizeof(u64);
 
        /* flush3 (dimm3) */
-       flush = nfit_buf + offset + sizeof(struct acpi_nfit_flush_address) * 3;
+       flush = nfit_buf + offset + flush_hint_size * 3;
        flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS;
-       flush->header.length = sizeof(struct acpi_nfit_flush_address);
+       flush->header.length = flush_hint_size;
        flush->device_handle = handle[3];
-       flush->hint_count = 1;
-       flush->hint_address[0] = t->flush_dma[3];
+       flush->hint_count = NUM_HINTS;
+       for (i = 0; i < NUM_HINTS; i++)
+               flush->hint_address[i] = t->flush_dma[3] + i * sizeof(u64);
 
        if (t->setup_hotplug) {
-               offset = offset + sizeof(struct acpi_nfit_flush_address) * 4;
+               offset = offset + flush_hint_size * 4;
                /* dcr-descriptor4: blk */
                dcr = nfit_buf + offset;
                dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION;
                dcr->header.length = sizeof(struct acpi_nfit_control_region);
                dcr->region_index = 8+1;
-               dcr->vendor_id = 0xabcd;
-               dcr->device_id = 0;
-               dcr->revision_id = 1;
+               dcr_common_init(dcr);
                dcr->serial_number = ~handle[4];
                dcr->code = NFIT_FIC_BLK;
                dcr->windows = 1;
@@ -1196,9 +1187,7 @@ static void nfit_test0_setup(struct nfit_test *t)
                dcr->header.length = offsetof(struct acpi_nfit_control_region,
                                window_size);
                dcr->region_index = 9+1;
-               dcr->vendor_id = 0xabcd;
-               dcr->device_id = 0;
-               dcr->revision_id = 1;
+               dcr_common_init(dcr);
                dcr->serial_number = ~handle[4];
                dcr->code = NFIT_FIC_BYTEN;
                dcr->windows = 0;
@@ -1300,10 +1289,12 @@ static void nfit_test0_setup(struct nfit_test *t)
                /* flush3 (dimm4) */
                flush = nfit_buf + offset;
                flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS;
-               flush->header.length = sizeof(struct acpi_nfit_flush_address);
+               flush->header.length = flush_hint_size;
                flush->device_handle = handle[4];
-               flush->hint_count = 1;
-               flush->hint_address[0] = t->flush_dma[4];
+               flush->hint_count = NUM_HINTS;
+               for (i = 0; i < NUM_HINTS; i++)
+                       flush->hint_address[i] = t->flush_dma[4]
+                               + i * sizeof(u64);
        }
 
        post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA0_SIZE);
@@ -1339,7 +1330,16 @@ static void nfit_test1_setup(struct nfit_test *t)
        spa->address = t->spa_set_dma[0];
        spa->length = SPA2_SIZE;
 
-       offset += sizeof(*spa);
+       /* virtual cd region */
+       spa = nfit_buf + sizeof(*spa);
+       spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
+       spa->header.length = sizeof(*spa);
+       memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_VCD), 16);
+       spa->range_index = 0;
+       spa->address = t->spa_set_dma[1];
+       spa->length = SPA_VCD_SIZE;
+
+       offset += sizeof(*spa) * 2;
        /* mem-region0 (spa0, dimm0) */
        memdev = nfit_buf + offset;
        memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP;
@@ -1365,9 +1365,7 @@ static void nfit_test1_setup(struct nfit_test *t)
        dcr->header.length = offsetof(struct acpi_nfit_control_region,
                        window_size);
        dcr->region_index = 0+1;
-       dcr->vendor_id = 0xabcd;
-       dcr->device_id = 0;
-       dcr->revision_id = 1;
+       dcr_common_init(dcr);
        dcr->serial_number = ~0;
        dcr->code = NFIT_FIC_BYTE;
        dcr->windows = 0;
@@ -1462,20 +1460,16 @@ static int nfit_test_probe(struct platform_device *pdev)
        nfit_test->setup(nfit_test);
        acpi_desc = &nfit_test->acpi_desc;
        acpi_nfit_desc_init(acpi_desc, &pdev->dev);
-       acpi_desc->nfit = nfit_test->nfit_buf;
        acpi_desc->blk_do_io = nfit_test_blk_do_io;
        nd_desc = &acpi_desc->nd_desc;
        nd_desc->provider_name = NULL;
+       nd_desc->module = THIS_MODULE;
        nd_desc->ndctl = nfit_test_ctl;
-       acpi_desc->nvdimm_bus = nvdimm_bus_register(&pdev->dev, nd_desc);
-       if (!acpi_desc->nvdimm_bus)
-               return -ENXIO;
 
-       rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_size);
-       if (rc) {
-               nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
+       rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_buf,
+                       nfit_test->nfit_size);
+       if (rc)
                return rc;
-       }
 
        if (nfit_test->setup != nfit_test0_setup)
                return 0;
@@ -1483,22 +1477,16 @@ static int nfit_test_probe(struct platform_device *pdev)
        nfit_test->setup_hotplug = 1;
        nfit_test->setup(nfit_test);
 
-       rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_size);
-       if (rc) {
-               nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
+       rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_buf,
+                       nfit_test->nfit_size);
+       if (rc)
                return rc;
-       }
 
        return 0;
 }
 
 static int nfit_test_remove(struct platform_device *pdev)
 {
-       struct nfit_test *nfit_test = to_nfit_test(&pdev->dev);
-       struct acpi_nfit_desc *acpi_desc = &nfit_test->acpi_desc;
-
-       nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
-
        return 0;
 }
 
@@ -1523,12 +1511,6 @@ static struct platform_driver nfit_test_driver = {
        .id_table = nfit_test_id,
 };
 
-#ifdef CONFIG_CMA_SIZE_MBYTES
-#define CMA_SIZE_MBYTES CONFIG_CMA_SIZE_MBYTES
-#else
-#define CMA_SIZE_MBYTES 0
-#endif
-
 static __init int nfit_test_init(void)
 {
        int rc, i;
@@ -1538,7 +1520,6 @@ static __init int nfit_test_init(void)
        for (i = 0; i < NUM_NFITS; i++) {
                struct nfit_test *nfit_test;
                struct platform_device *pdev;
-               static int once;
 
                nfit_test = kzalloc(sizeof(*nfit_test), GFP_KERNEL);
                if (!nfit_test) {
@@ -1577,20 +1558,6 @@ static __init int nfit_test_init(void)
                        goto err_register;
 
                instances[i] = nfit_test;
-
-               if (!once++) {
-                       dma_addr_t dma;
-                       void *buf;
-
-                       buf = dma_alloc_coherent(&pdev->dev, SZ_128M, &dma,
-                                       GFP_KERNEL);
-                       if (!buf) {
-                               rc = -ENOMEM;
-                               dev_warn(&pdev->dev, "need 128M of free cma\n");
-                               goto err_register;
-                       }
-                       dma_free_coherent(&pdev->dev, SZ_128M, buf, dma);
-               }
        }
 
        rc = platform_driver_register(&nfit_test_driver);
index 96c5e16..9f18e2a 100644 (file)
@@ -12,6 +12,7 @@
  */
 #ifndef __NFIT_TEST_H__
 #define __NFIT_TEST_H__
+#include <linux/list.h>
 
 struct nfit_test_resource {
        struct list_head list;
@@ -26,4 +27,5 @@ void __iomem *__wrap_ioremap_nocache(resource_size_t offset,
 void __wrap_iounmap(volatile void __iomem *addr);
 void nfit_test_setup(nfit_test_lookup_fn lookup);
 void nfit_test_teardown(void);
+struct nfit_test_resource *get_nfit_res(resource_size_t resource);
 #endif